The ? Operator
The ? operator is syntactic sugar for automatic propagation: if the value is
Result::Ok(v), it extracts v; if it is Result::Err(e), it immediately
returns the error to the caller. The effect is the same as match + return,
but without the visual noise.
The file below compares the verbose form with the concise form and shows that
? also works with T? (optional):
? on Result and on Option: clean propagation without manual if/match.
03-try-operator.zolo
// Feature: `?` operator — automatic propagation
// Syntax: `let x = expr?` (extracts Ok or returns Err)
// When to use: chain Result-returning calls without boilerplate.
use std::Result
fn divide(a: int, b: int) -> Result<int, str> {
if b == 0 {
return Result.Err("division by zero")
}
return Result.Ok(a / b)
}
// Without `?` — nested match, verbose:
fn compute_verbose(a: int, b: int, c: int) -> Result<int, str> {
let r1 = divide(a, b)
if r1.is_err() {
return r1
}
let x = r1.unwrap()
let r2 = divide(x, c)
if r2.is_err() {
return r2
}
return Result.Ok(r2.unwrap())
}
// With `?` — clean:
fn compute(a: int, b: int, c: int) -> Result<int, str> {
let x = divide(a, b)? // if Err, returns Err immediately
let y = divide(x, c)? // same here
return Result.Ok(y)
}
fn describe(r: Result<int, str>) {
match r {
Result::Ok(v) => print("ok: {v}"),
Result::Err(e) => print("error: {e}"),
}
}
describe(compute(100, 4, 5))
// expected: ok: 5
describe(compute(100, 0, 5))
// expected: error: division by zero
describe(compute(100, 4, 0))
// expected: error: division by zero
// Verbose and short forms produce the same result:
describe(compute_verbose(100, 4, 5)) // ok: 5
describe(compute_verbose(100, 0, 5)) // error: division by zero
// `?` also works with Option (T?). If None/nil, returns nil.
fn first(arr: [int]) -> int? {
if arr.len() == 0 {
return nil
}
return arr[0]
}
fn sum_firsts(a: [int], b: [int]) -> int? {
let x = first(a)?
let y = first(b)?
return x + y
}
print(sum_firsts([1, 2], [3, 4])) // 4
print(sum_firsts([], [3, 4])) // nil
print(sum_firsts([1], [])) // nil
The function that uses
?must have a compatible return type:Result<_, E>forResult, orT?for optionals.
Challenge
Try calling compute(100, 4, 0) and compute(0, 1, 1). Which step in the
chain triggers the error in each case? Change divide to return 0 instead of
Err when b == 0 and observe what changes.