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

Store owned closures

A generic record can own a callback’s captured state. You do not need to name the closure’s concrete type: the constructor infers it.

class Handler[F: Callable[[i64], Result[i64, OverflowError[i64]]]]:
    callback: F
    def call(self: &mut Handler[F], amount: i64) -> Result[i64, OverflowError[i64]]:
        self.callback(amount)

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

def main() -> Result[(), IoError | OverflowError[i64]]:
    mut first = Handler(counter(10))
    mut second = Handler(counter(100))
    print(first.call(3)?)?
    print(second.call(7)?)?
    print(first.callback(2)?)?
    Ok(())
13
107
15

The Callable constraint checks the signature without erasing the concrete environment type. Each record stores its environment inline.

Keep captured state owned when storing a callback. A closure borrowing a local cannot enter a record. Moving the record transfers ownership; dropping it cleans up captured resources. Closures do not support copy or equality.