Errors and optionality
Albite has no exceptions. A function that might not produce a value says so in its return type, and the caller has to deal with it.
Option
Option<T> is a value that may be absent:
pub type Option<T> = None | Some(T)
pub fn unwrap_or(opt: Option<Nat>, default: Nat) -> Nat {
match opt {
None() => default,
Some(x) => x,
}
}
Result
Result<T, E> is a value or an explanation of why there isn’t one:
pub type Result<T, E> = Ok(T) | Err(E)
fn parse(n: Nat) -> Result<Nat, String> {
if n == 0 { Err("zero") } else { Ok(n) }
}
Constructor order matters to the compiler’s encoding: Ok is declared first and
so is the left alternative. Keep the conventional order.
The ? operator
Since 1.5
Matching on every intermediate Result buries the logic. ? unwraps a success
and returns early on failure:
fn sum_two(a: Nat, b: Nat) -> Result<Nat, String> {
let x = parse(a)?;
let y = parse(b)?;
Ok(x + y)
}
Without it, the same function is three nested match expressions. ? requires
the enclosing function to return a compatible Result (or Option), because
that is what it returns early with.
try blocks
Since 1.5
A try block produces a Result without needing a function boundary, so ?
can be used over a smaller region:
fn total(a: Nat, b: Nat) -> Nat {
let r: Result<Nat, String> = try {
let x = parse(a)?;
let y = parse(b)?;
x + y
};
match r { Ok(n) => n, Err(_) => 0 }
}
Two things to note. The block’s body produces the success value — try
wraps it in Ok for you, so the tail is x + y and not Ok(x + y). And a
try block cannot infer its own type, so the binding needs an annotation;
without one the compiler will say so.
A known limitation. A
tryblock whose body uses?type-checks but currently fails to compile to native code. Atryblock without?is fine, and?at function scope is fine — it is specifically the combination. See Current limitations.
Which to use
Use Option when absence needs no explanation — a lookup that found nothing.
Use Result when the caller would want to know why, and put something useful
in the error rather than a bare false. Use ? once a function has more than
one fallible step, and try when the fallible region is smaller than the
function containing it.