Error Handling
Recoverable failures, Result<T>, Option<T>, propagation, and exception boundaries.
Result
Result<T> is for recoverable failures that are part of a function contract.
Ok(value)carries the successful value.Err(message)carries a human-readable error.- The caller must handle, unwrap, transform, or propagate the result.
- Use
Resultwhen the function author expects the caller to make a decision.
fn read_config(path: str) -> Result<Config> {
let text = fs.read(path)?
let cfg = json.decode::<Config>(text)?
Ok(cfg)
}Propagation with `?`
? keeps the happy path visible while preserving explicit failure flow.
Applied to Result, ? unwraps Ok(v) into v and returns Err(e) from the current function. Applied to Option, it unwraps Some(v) and returns absence on None. It only makes sense inside a function whose return type can represent that early exit.
Option
Option<T> is the explicit API-facing form of absence.
- Use
Option<T>in signatures when absence is part of the contract. - Use
T | nilwhen local flow benefits from the lighter spelling. - Use
map,unwrap_or, and?to avoid noisy one-arm matches. - Use a full match when both absence and presence need meaningful behaviour.
Exception boundary
try and catch are for external systems that throw instead of returning values.
The language keeps value-based errors and exception-style failures separate. Inside La3 code, failures should normally be Result. At the boundary with a database, network library, operating system, or foreign code that throws, try and catch mark the translation point.
- Typed catches handle expected external failures.
- A final untyped catch can report or convert unexpected failures.
finallyis for cleanup that must happen regardless of outcome.