Effects in the type
Functions are pure by default; touching IO requires !io on the signature — the signature tells you whether it reaches outside, so testing a pure function needs no mocks. A second axis is named effects you declare yourself: effect declares the operations, with handle answers them on the spot, and the label propagates along signatures until exactly one syntactic node subtracts it. That tier is specified, implemented on both backends and tested, and it has no internal consumer yet: neither the standard library nor the compiler declares a named effect.
effect Ask {
fn ask() -> Int
}
# Pure. The signature says it asks; it does not say whom
fn total() -> Int !Ask = ask() + ask()
pub fn main() -> Unit !io = {
with handle Ask { ask() => 21 }
println("${total()}")
}
42