06 · Effects
Sigil’s effect system lets you declare named capabilities, perform them inside functions, and install handle/with blocks at the call site to decide what those capabilities actually do. This cleanly separates what a computation needs from how that need is satisfied — no global state, no hidden coupling.
// Declare an effect with one or more operations.effect Log { fn write(level: str, msg: str) -> ()}
// This function needs the Log capability — declared with !Log.fn process(items: &[i32]) !Log !io { perform Log::write("INFO", "starting process"); for item in items { if item < 0 { perform Log::write("WARN", "negative value encountered"); } println!("{}", item * 2); } perform Log::write("INFO", "done");}
fn main() !io { // Install a handler that routes Log operations to stderr. handle process(&[1, -2, 3]) with { Log::write(level, msg) => { eprintln!("[{}] {}", level, msg); resume(()) // resume the suspended computation } }}Output
Section titled “Output”[INFO] starting process2[WARN] negative value encountered-46[INFO] doneWhat the compiler sees
Section titled “What the compiler sees”perform Log::write(...) suspends the computation at that point and transfers control to the nearest enclosing handle block for Log. The resume(()) call in the handler resumes execution where it was suspended, passing the handler’s return value back. A function that performs Log without an enclosing handler is a compile error — the effect must be handled or propagated via !Log on the caller’s signature.
Next → 07 · Traits