# Results
A Result is Deft's explicit success/failure value: `%Ok{ :value v }`
for success and `%Err{ :message m }` for failure. Both are tagged maps,
so field access (`$r~value`, `$r~message`) and pattern matching work on
them directly. The bare functions below construct, test, and extract
Results and are compiled into every runtime — no import needed. For the
language conventions around `try`/`catch` and Result-returning
functions, see Error Handling.
## Functions
| Function | Purpose |
|---|---|
| `ok value` | Construct `%Ok{ :value value }` |
| `err message` | Construct `%Err{ :message message }` |
| `ok? x` | True when `x` is an `%Ok` |
| `err? x` | True when `x` is an `%Err` |
| `unwrap result ?default` | Extract the `:value` of an `%Ok`, the `:message` of an `%Err`, or `default` when given |
| `throw value` | Raise an error, jumping to the nearest enclosing `try` |
| `ok! expr` / `$expr(ok!)` | Assert `%Ok` and return its `:value`; on `%Err`, return from the enclosing function |
| `err! expr` / `$expr(err!)` | Assert `%Err` and return its `:message`; on `%Ok`, return from the enclosing function |
`[ok v]` is equivalent to the literal `%Ok{ value v }`, and `[err m]`
to `%Err{ message m }`; the constructors are convenient when wrapping a
computed value.
`unwrap` returns the `:value` of an `%Ok`; for an `%Err` it returns the
supplied default, or the `:message` when no default is given. The
default is only consulted on failure, and non-Result values pass
through unchanged.
`throw` accepts any value. A string is conventional and is what a catch
binds; throwing a full `%Err` map preserves extra fields:
[throw "not found"] [throw %Err{ :message "invalid input" :code 422 }]
`ok!` and `err!` are compiler-intercepted: both `[ok! $expr]` and the
postfix `$expr(ok!)` emit inline opcodes instead of a function call, so
they must appear inside a function body where the short-circuit return
is meaningful. Non-Result values pass through both verbs unchanged.
The namespaced helpers `result/map`, `result/sequence`, and
`result/traverse` lift functions over Results and collapse collections
of Results; `and-then` is the monadic bind. All are reference-documented
per symbol.
## Examples
def fetch-user {|id^number| if ($id < 0) { return [err "bad id"] } [ok %{ :id $id :name "Alice" }] } set r [fetch-user 7] [ok? $r] # => true [err? $r] # => false $r~value~name # => "Alice"
Branch with the predicates, or destructure with `match`:
if [ok? $r] { echo "name:" $r~value~name } else { echo "failed:" $r~message } match $r { %Ok{ value $v } => echo "got $v" %Err{ message $m } => echo "error: $m" }
`unwrap` is the quick way out; the two-argument form substitutes a
default for `%Err`:
[unwrap [ok 42]] # => 42 [unwrap [err "nope"]] # => "nope" — the message [unwrap [err "nope"] 0] # => 0 — the default $r(unwrap) # => %{ :id 7 :name "Alice" }
`ok!` unwraps or returns early from the enclosing function — the
idiomatic way to thread Results through a happy path:
def inc-or-fail {|x| if ($x > 100) { return [err "too big"] } else { return [ok ($x + 1)] } } def go {|x| set v [ok! [inc-or-fail $x]] # on %Err, go returns that Err ($v * 10) } [go 4] # => 50 [go 200] # => %Err{:message "too big"}
`err!` is its mirror: it asserts failure and extracts the message,
returning early when the value is an `%Ok`:
def describe {|r| set msg [err! $r] # on %Ok, describe returns that Ok [str "failed: " $msg] } [describe [err "disk full"]] # => "failed: disk full" [describe [ok 42]] # => %Ok{:value 42}
`throw` inside a `try` hands control to the catch:
try { [throw "x must be non-negative"] } catch e { echo "caught:" $e # caught: x must be non-negative }
## See Also
- Error Handling — `try`/`catch`, `throw`, Result conventions
- Types — `%Ok`/`%Err` are tagged maps; `type` and `is?`
- Pattern Matching — destructuring Results in `match`