Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Return a closure

Return an owned closure to keep its captured data after its creating function returns. Closure describes the returned call signature:

def counter(start: i64) -> Closure[[], Result[i64, OverflowError[i64]]]:
    def [mut start]() -> Result[i64, OverflowError[i64]]:
        start = start + 1
        Ok(start)

def apply(f: &mut Closure[[], Result[i64, OverflowError[i64]]]) -> Result[i64, OverflowError[i64]]:
    f()

def main() -> Result[(), IoError | OverflowError[i64]]:
    mut first = counter(10)
    mut second = counter(30)
    print(apply(&mut first)?)?
    print(second()?)?
    print(first()?)?
    Ok(())
11
31
12

apply needs an exclusive borrow because calling the counter changes its state. For a read-only closure, use a shared parameter such as &Closure[[i64], Result[i64, OverflowError[i64]]].

Different anonymous expressions have different concrete environment types, even with identical signatures. A factory must return one concrete type on every path. Borrowing closures cannot escape their creating function. To return different owned shared-call environments, explicitly allocate a BoxedCallable.

An owned closure can capture another closure or be wrapped in Option or Result:

def make(offset: i64) -> Option[Closure[[i64], Result[i64, OverflowError[i64]]]]:
    inner = def [offset](value: i64) -> Result[i64, OverflowError[i64]]:
        Ok(offset + value)
    outer = def [inner](value: i64) -> Result[i64, OverflowError[i64]]:
        Ok(inner(value)? * 2)
    Some(outer)

def main() -> Result[(), IoError | OverflowError[i64]]:
    match make(3):
        case Some(calculate):
            print(calculate(4)?)?
        case Nothing:
            print("no callback")?
    Ok(())
14

Captured resources drop in reverse capture order, including nested environments.

You can call a returned closure immediately, for example counter(10)(). Its environment remains alive through the complete expression and is then dropped. ? in a later argument also cleans up that temporary. Match an optional closure before calling it, as in the example above.