13 · Error Handling
Sigil handles recoverable errors through the effect system rather than exceptions or panic. Declare a Fail effect, perform it when something goes wrong, and install a handle/with block at the call site to decide what happens. The error path is visible in the function’s type — callers cannot accidentally ignore a function that may fail.
// A typed failure effect. E is the error payload.effect Fail<E> { fn raise(err: E) -> ! // ! = never returns normally}
// Parse a positive integer — fails with a message on bad input.fn parse_positive(s: str) -> i32 !Fail<str> { match s.parse::<i32>() { Ok(n) if n > 0 => n, Ok(_) => perform Fail::raise("must be positive"), Err(_) => perform Fail::raise("not a valid integer"), }}
// Divide — fails on zero denominator.fn safe_div(a: i32, b: i32) -> i32 !Fail<str> { if b == 0 { perform Fail::raise("division by zero") } else { a / b }}
fn main() !io { // Handle parse_positive — recover with a default. let n = handle parse_positive("42") with { Fail::raise(msg) => { println!("Parse error: {}", msg); resume(0) // resume with a fallback value } }; println!("parsed: {}", n); // 42
// Demonstrate failure path. let m = handle parse_positive("-5") with { Fail::raise(msg) => { println!("Parse error: {}", msg); resume(0) } }; println!("parsed: {}", m); // 0 (fallback)
// Chained failure — safe_div inside a handler. let result = handle safe_div(10, 0) with { Fail::raise(msg) => { println!("Math error: {}", msg); resume(-1) } }; println!("result: {}", result); // -1}Output
Section titled “Output”parsed: 42Parse error: must be positiveparsed: 0Math error: division by zeroresult: -1What the compiler sees
Section titled “What the compiler sees”!Fail<str> in the function signature is a static promise: this function may fail with a str error. A caller that doesn’t install a handle/with block must propagate !Fail<str> in its own signature. There is no way to call parse_positive and silently drop the failure path — the compiler will reject it. Unlike exceptions, Fail effects are tracked per-type, so !Fail<ParseError> and !Fail<IoError> are distinct effects that can be handled independently.
Next → 14 · Modules