How does the Result type work in EK9?
← Getting Started · Ref: Q48
Result of (O, E) is a generic type for operations producing a success value, error value, or BOTH. Unlike Rust's either/or Result, EK9's can hold both simultaneously.
FOUR POSSIBLE STATES
1. Neither ok nor error: Result() of (String, Integer)
2. Ok only: Result("Steve", Integer())
3. Error only: Result(String(), -1)
4. Both ok AND error: Result("Default", -1)
The fourth state handles cases like a failed config lookup that still returns a fallback with an error code.
RESULT CREATION
r1 <- Result("Steve", Integer()) two-arg, ok only r2 <- Result() of (String, Integer) empty r3 <- (Result() of (String, Integer)).asOk("Steve") factory r4 <- (Result() of (String, Integer)).asError(-1) factory
CHECKING STATE
if r? checks isOk if r.isOk() explicit ok check if r.isError() explicit error check r is empty neither ok nor error
isOk() and isError() are INDEPENDENT — both can be true.
BASIC GUARD PATTERNS
Compiler enforces guard-before-access:
if r <- getResult() okData <- r.ok() if r.isError() errData <- r.error()
OK OR DEFAULT / ERROR OR DEFAULT
assured <- r.okOrDefault("fallback") errVal <- r.errorOrDefault(0)
See Q86 for advanced guard patterns. See Q87 for Result operations (whenOk/whenError, merge, copy, comparison, iterator, contains). See Q47 for Optional. See Q29 for tri-state semantics. See Q54 for Consumer/Acceptor. See Q126 for choosing collection types.
Use 'ek9 -h Result' for the full API.
See Q139 for try/catch vs Result. See Q243 for coalescing operators. See Q251 for unset variable errors. See Q259 for four-state Result design. See Q316 for discarded Result errors.
Example
defines module qa.result defines function <?- Returns a Result with ok value set. -?> getOkResult() <- rtn <- Result("Steve", Integer()) <?- Returns a Result with error value set. -?> getErrorResult() <- rtn <- Result(String(), -1) <?- Returns a Result with both ok and error set. -?> getBothResult() <- rtn <- Result("Default", -1) <?- Returns an empty Result. -?> getEmptyResult() <- rtn <- Result() of (String, Integer) defines program ResultBasics() stdout <- Stdout() // === FOUR STATES === okResult <- Result("Steve", Integer()) errorResult <- Result(String(), -1) bothResult <- Result("Default", -1) emptyResult <- Result() of (String, Integer) stdout.println(`Ok result: ${okResult}`) stdout.println(`Error result: ${errorResult}`) stdout.println(`Both result: ${bothResult}`) stdout.println(`Empty result: ${emptyResult}`) // === CHECKING STATE === // ? checks isOk, isOk/isError are independent stdout.println(`okResult?: ${okResult?}, isOk: ${okResult.isOk()}, isError: ${okResult.isError()}`) stdout.println(`errorResult?: ${errorResult?}, isOk: ${errorResult.isOk()}, isError: ${errorResult.isError()}`) stdout.println(`bothResult?: ${bothResult?}, isOk: ${bothResult.isOk()}, isError: ${bothResult.isError()}`) stdout.println(`emptyResult is empty: ${emptyResult is empty}`) // === CREATION WITH FACTORY METHODS === factoryOk <- (Result() of (String, Integer)).asOk("Alice") factoryErr <- (Result() of (String, Integer)).asError(99) stdout.println(`Factory ok: ${factoryOk}`) stdout.println(`Factory error: ${factoryErr}`) // === BASIC GUARD PATTERNS === // Declaration guard — ? check implied if r <- getOkResult() okData <- r.ok() stdout.println(`Declaration guard: ${okData}`) // Explicit isOk check r1 <- getOkResult() if r1.isOk() stdout.println(`isOk guard: ${r1.ok()}`) // Explicit isError check r2 <- getErrorResult() if r2.isError() stdout.println(`isError guard: ${r2.error()}`) // Dual guard — both ok and error r3 <- getBothResult() if r3.isOk() stdout.println(`Both ok side: ${r3.ok()}`) if r3.isError() stdout.println(`Both error side: ${r3.error()}`) // Empty result — neither guard enters if r4 <- getEmptyResult() stdout.println("Should not print") // === OK OR DEFAULT / ERROR OR DEFAULT === r5 <- getOkResult() assured <- r5.okOrDefault("Fallback") stdout.println(`okOrDefault (set): ${assured}`) r6 <- getEmptyResult() defaulted <- r6.okOrDefault("Fallback") stdout.println(`okOrDefault (empty): ${defaulted}`) r7 <- getErrorResult() errVal <- r7.errorOrDefault(0) stdout.println(`errorOrDefault (set): ${errVal}`) r8 <- getEmptyResult() errDefault <- r8.errorOrDefault(0) stdout.println(`errorOrDefault (empty): ${errDefault}`)
Common mistakes
E08030 — Calling .ok() on a Result without first checking isOk() triggers E08030 — has not been checked before access. The compiler enforces guard-before-access for both .ok() and .error(). See ek9 -h E08030 for details.
Incorrect:
stdout.println(`isOk guard: ${r1.ok()}`)
Correct:
if r1.isOk() stdout.println(`isOk guard: ${r1.ok()}`)
E06190 — Result requires two different types for ok and error values. Using the same type for both triggers E06190 — Result must be used with two different types. This ensures the compiler can distinguish ok from error. See ek9 -h E06190 for details.
Incorrect:
okResult <- Result("Steve", String())
Correct:
okResult <- Result("Steve", Integer())
E11052 — Calling a function that returns Result but discarding the result triggers E11052 — Result or Optional result is discarded and must always be checked. Always assign and check Results. See ek9 -h E11052 for details.
Incorrect:
getOkResult()
assured <- getOkResult().okOrDefault("Fallback")
Correct:
r5 <- getOkResult() assured <- r5.okOrDefault("Fallback")
Other ways to ask this
- How do I handle success and error values in EK9?
- What is the difference between Result and Optional in EK9?
- How do I safely access ok and error values from a Result?
- How do I handle errors without exceptions in EK9?
- What do I use instead of try-catch in EK9?
- How do I handle a function that might fail in EK9?
Coming from another language?
Java: no Result, try-catch. Rust: Result<T,E> either/or only, .unwrap() panics. Go: (value, error) tuple, no enforcement. Kotlin/Swift: Result exists but no compiler-enforced access. EK9: four states (both ok AND error), compiler-enforced guards, okOrDefault/errorOrDefault.
Keywords: fail, first, failure, catch, isOk, safe, intro, swift, isError, guard, ok, errorOrDefault, beginner, error, okOrDefault, null-safe, try, start, compiler, result, handle, type, isset, success, migrate, exception