Albite

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 try block whose body uses ? type-checks but currently fails to compile to native code. A try block 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.