What operations and callbacks does Result support?
← Getting Started · Ref: Q87
Result supports callbacks, factory methods, operators for comparison, copy, merge, and conversions beyond basic guard access.
WHEN OK / WHEN ERROR CALLBACKS
r.whenOk(myConsumer) called only if ok present r.whenError(errorConsumer) called only if error present
Consumer is pure. Acceptor is non-pure (can mutate/do I/O). Callback never invoked if value absent.
CONTAINS
r contains "Steve" true if isOk AND ok equals argument
ITERATOR
Yields 0 or 1 elements over the ok value:
while iter <- r.iterator() then iter.hasNext() item :=: iter.next()
FACTORY METHODS
justOk <- r.asOk("Steve") ok only justErr <- r.asError(-1) error only cleared <- r.asEmpty() neither set
MERGE (:~:)
Fills unset sides from another Result without overwriting:
r1 :~: r2
Ideal for layering defaults.
COPY (:=:), COMPARISON (== <>)
Deep copy: target :=: source. Two empty Results are equal.
STRING ($), JSON ($$), HASHCODE (#?)
$r, $$r, #? r
See Q48 for Result basics. See Q86 for Result guards. See Q54 for Consumer/Acceptor. See Q29 for tri-state. See Q139 for Result vs try/catch. See Q259 for four-state design.
Example
defines module qa.result.operations defines function <?- Returns a Result with ok value set. -?> getOkResult() <- rtn <- Result("Steve", Integer()) <?- Pure consumer for ok values. -?> okProcessor() as pure -> okContent as String require okContent? <?- Pure consumer for error values. -?> errorProcessor() as pure -> code as Integer require code? defines program ResultOperationsDemo() stdout <- Stdout() // === WHEN OK / WHEN ERROR CALLBACKS === // Pure Consumer callbacks — read-only okOnly <- Result("Steve", Integer()) okOnly.whenOk(okProcessor) stdout.println("whenOk with Consumer: called on ok Result") errOnly <- Result(String(), -1) errOnly.whenError(errorProcessor) stdout.println("whenError with Consumer: called on error Result") // Callbacks on Result with both values both <- Result("Default", -1) both.whenOk(okProcessor) both.whenError(errorProcessor) stdout.println("Both callbacks fired on dual-value Result") // Callback NOT fired when value absent emptyResult <- Result() of (String, Integer) emptyResult.whenOk(okProcessor) emptyResult.whenError(errorProcessor) stdout.println("Empty Result: neither callback fires") // === CONTAINS === stdout.println(`contains Steve: ${okOnly contains "Steve"}`) stdout.println(`contains Other: ${okOnly contains "Other"}`) stdout.println(`error contains: ${errOnly contains "Steve"}`) // === ITERATOR === extracted <- String() while iter <- okOnly.iterator() then iter.hasNext() extracted :=: iter.next() stdout.println(`Iterator ok: ${extracted}`) // Empty Result iterator yields nothing noItems <- String() while iter <- emptyResult.iterator() then iter.hasNext() noItems :=: iter.next() stdout.println(`Iterator empty: ${noItems?}`) // === FACTORY METHODS === prototype <- Result("Proto", 99) justOk <- prototype.asOk("Fresh") require justOk.isOk() and not justOk.isError() stdout.println(`asOk: ${justOk}`) justErr <- prototype.asError(42) require not justErr.isOk() and justErr.isError() stdout.println(`asError: ${justErr}`) cleared <- prototype.asEmpty() require cleared is empty stdout.println(`asEmpty: ${cleared}`) // === MERGE (:~:) === m1 <- Result("Steve", Integer()) m2 <- Result(String(), -1) m1 :~: m2 require m1.isOk() and m1.isError() stdout.println(`Merged: ${m1}`) // Merge does not overwrite existing ok m3 <- Result("Keep", Integer()) m4 <- Result("Overwrite", -2) m3 :~: m4 if m3.isOk() stdout.println(`Merge kept ok: ${m3.ok()}`) // === COPY (:=:) === original <- Result("Alice", 7) copied <- Result() of (String, Integer) copied :=: original require copied == original stdout.println(`Copied: ${copied}`) // === COMPARISON (== and <>) === c1 <- Result("A", 1) c2 <- Result("A", 1) c3 <- Result("B", 2) stdout.println(`c1 == c2: ${c1 == c2}`) stdout.println(`c1 <> c3: ${c1 <> c3}`) // Empty Results are equal e1 <- Result() of (String, Integer) e2 <- Result() of (String, Integer) stdout.println(`empty == empty: ${e1 == e2}`) // === STRING ($), JSON ($$), HASHCODE (#?) === display <- Result("Steve", 42) stdout.println(`String: ${display}`) stdout.println(`JSON: ${$ display}`) stdout.println(`Hash: ${#? display}`)
Common mistakes
E08130 — Calling a non-pure function like getOkResult() from within a pure function triggers E08130 — not marked pure but call is made in a pure scope. Pure functions cannot call non-pure functions. See ek9 -h E08130 for details.
Incorrect:
okProcessor() as pure -> okContent as String result <- getOkResult() require okContent?
Correct:
okProcessor() as pure -> okContent as String require okContent?
E06190 — Result requires two different types for ok and error. 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:
Result("Steve", String())
Correct:
Result("Steve", Integer())
Other ways to ask this
- How do whenOk and whenError callbacks work on Result?
- How do I compare or copy Result values in EK9?
- How does the merge operator work with Result?
Coming from another language?
Java: no Result, CompletableFuture callbacks no compile safety. Rust: map/and_then, no merge, either/or only. Go: (value, error) tuple, manual checks. EK9: whenOk/whenError callbacks, :~: merge, :=: copy, contains, iterator, factory methods, compile-time safety.
Keywords: copy, asEmpty, whenError, contains, whenOk, json, guard, result, error, callback, acceptor, ok, asOk, string, operations, iterator, start, asError, intro, first, hashcode, comparison, consumer, merge, beginner