How do I safely extract the ok or error value from a Result?

← Safe Value Access · Ref: Q164

EK9 Results require compiler-enforced guards before accessing ok or error values. The isOk() guard unlocks .ok(), and the isError() guard unlocks .error(). Neither unlocks the other.

ISOK GUARD THEN OK

Check isOk() before accessing the ok value:

  if r.isOk()
    okVal <- r.ok()

The compiler verifies isOk() was checked before allowing .ok().

ISERROR GUARD THEN ERROR

Check isError() before accessing the error value:

  if r.isError()
    errVal <- r.error()

DUAL GUARD PATTERN

Handle both sides independently:

  if r.isOk()
    process(r.ok())
  else if r.isError()
    handleError(r.error())

OKORDEFAULT AND ERRORORDEFAULT

Extract with a fallback, no guard needed:

  okVal <- r.okOrDefault("fallback")
  errVal <- r.errorOrDefault(-1)

Always returns a usable value.

TERNARY GUARD

Compact single-expression extraction:

  okVal <- r.isOk() <- r.ok() else "default"
  errVal <- r.isError() <- r.error() else 0

See Q48 for Result basics. See Q86 for Result guard patterns. See Q87 for Result operations and callbacks.

Example

defines module qa.safeaccess.resultsafe

  defines function

    getOkResult()
      <- rtn <- Result("Success", Integer())

    getErrorResult()
      <- rtn <- Result(String(), 42)

  defines program
    ResultExtractDemo()
      stdout <- Stdout()

      // === ISOK GUARD THEN OK ===

      r1 <- getOkResult()
      if r1.isOk()
        okVal <- r1.ok()
        stdout.println(`Ok value: ${okVal}`)

      // === ISERROR GUARD THEN ERROR ===

      r2 <- getErrorResult()
      if r2.isError()
        errVal <- r2.error()
        stdout.println(`Error value: ${errVal}`)

      // === DUAL GUARD PATTERN ===

      r3 <- getOkResult()
      if r3.isOk()
        stdout.println(`Dual ok: ${r3.ok()}`)
      else if r3.isError()
        stdout.println(`Dual error: ${r3.error()}`)

      // === ? OPERATOR (SHORTHAND FOR ISOK) ===

      r4 <- getOkResult()
      if r4?
        stdout.println(`? guard ok: ${r4.ok()}`)

      // === OKORDEFAULT / ERRORORDEFAULT ===

      r5 <- getOkResult()
      safeOk <- r5.okOrDefault("fallback")
      stdout.println(`okOrDefault (ok result): ${safeOk}`)

      r6 <- getErrorResult()
      safeOk2 <- r6.okOrDefault("fallback")
      stdout.println(`okOrDefault (error result): ${safeOk2}`)

      safeErr <- r6.errorOrDefault(-1)
      stdout.println(`errorOrDefault: ${safeErr}`)

      // === TERNARY GUARD ===

      r7 <- getOkResult()
      ternaryOk <- r7.isOk() <- r7.ok() else "default"
      stdout.println(`Ternary ok: ${ternaryOk}`)

      r8 <- getErrorResult()
      ternaryErr <- r8.isError() <- r8.error() else 0
      stdout.println(`Ternary error: ${ternaryErr}`)

Common mistakes

E50060 — Result does not have an isValid() method. The correct method for checking the success state is isOk(). Calling a non-existent method triggers E50060 — method not resolved. See ek9 -h E50060 for details.

Incorrect:

if r1.isValid()

Correct:

if r1.isOk()
Other ways to ask this
  • How do I unwrap a Result in EK9?
  • What is the safe way to access Result ok and error values?
  • How do I get the success or failure value from a Result in EK9?

Coming from another language?

Java: try-catch for error handling, no Result type, exceptions can be silently ignored. Python: try/except, no compile-time enforcement. Rust: Result.unwrap() panics, pattern matching enforced by compiler. Go: val, err := fn(); if err != nil is convention not enforcement. Kotlin: Result.getOrElse() for defaults, no compile-time guard enforcement. EK9: isOk()/isError() are compiler-enforced guards, okOrDefault()/errorOrDefault() for safe defaults, no escape hatches.

Keywords: error, okOrDefault, isset, access, debug, ok, null-safe, isError, safe, result, unwrap, extract, guard, isOk, default