Result[T, E] contains Ok(T) or Err(E).
loaded: Result[User, LoadError] = load_user(id)T ! E is equivalent.
loaded: User ! LoadError = load_user(id)The compact form is common in function signatures.
Construction
Construct the variants explicitly when working with a Result value.
success := Ok(42)
failure: int ! ParseError = Err(InvalidDigit { position: 0 })Inside a fallible function, a compatible success return can be written as the
bare success value, and error provides the error channel.
fn parse_digit(value: char): int ! ParseError {
if value < '0' or value > '9' {
error InvalidDigit { position: 0 }
}
return value.to_int() - '0'.to_int()
}Explicit return Ok(value) and return Err(error) are also accepted when the
wrapper makes control flow clearer.
Match
Use explicit variants for direct, unsurprising handling.
match load_user(id) {
Ok(user) => show(user)
Err(error) => show_error(error)
}Atoll can also infer success and known error-variant arms from the result’s
types, but explicit Ok/Err is preferable when a bare binding could be
ambiguous.
match load_user(id) {
user => show(user)
NotFound { id } => show_missing(id)
Err(error) => show_error(error)
}Match checking remains exhaustive over both channels.
Queries
is_ok, is_err, is_ok_and, and is_err_and inspect a result without
discarding its type.
retryable := result.is_err_and { error => error.is_retryable() }Use matching when the next operation needs the payload.
Success transforms
map changes Ok while preserving the same error type.
name := load_user(id).map { user => user.name }flat_map sequences another operation returning a compatible Result.
saved := validate(input).flat_map { value => save(value) }Error transforms
The catch syntax maps or handles the error side with exhaustive patterns.
mapped := read_config() catch {
Missing => ConfigError.NotFound
Invalid { message } => ConfigError.Invalid { message }
}See Catch for recovery and propagation behavior.
Fallback
unwrap_or and unwrap_or_else are total: they return a success payload or a
fallback.
value := attempt.unwrap_or(default_value)
value := attempt.unwrap_or_else { error => recover(error) }There is no panic-style unwrap.
or and or_else choose another result on failure. and sequences a result
that is already available. Prefer flat_map when the second computation
depends on the first payload.
Evaluation matters:
unwrap_or(value),or(result), andand(result)receive an already evaluated argument;unwrap_or_else,or_else, andflat_mapcall their closure only for the case that needs it.
Use the closure form when computing the alternative is expensive or has side effects.
Conversion
ok() discards the error and returns an Option[T]. Use it only when the
reason for failure is intentionally irrelevant.
maybe_user := load_user(id).ok()Converting an Option to a Result uses to_result(error).
Propagation
Postfix ? extracts Ok or returns Err through a compatible fallible
function.
fn load_name(id: int): string ! LoadError {
user := load_user(id)?
return user.name
}Compatibility includes propagation from a member error into a declared error
union. Unrelated error types require conversion with catch.
Handling discipline
A Result is an ordinary value, so it can be stored, returned, transformed,
or deliberately discarded. Code review and lints should treat accidental
discard as suspicious, but the language model does not turn Result into an
exception or hidden control channel.
Copying or retaining a result follows the ownership rules of both type arguments. Extracting a managed success or error payload transfers or retains it according to the selected operation; matching does not bypass normal cleanup.