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 stateful callbacks

Pair explicit state with a named function when a registry needs different callback bodies with the same state type and call signature:

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

def accumulate(total: &mut i64, value: i64) -> Result[i64, OverflowError[i64]]:
    *total = *total + value
    Ok(*total)

def subtract(total: &mut i64, value: i64) -> Result[i64, OverflowError[i64]]:
    *total = *total - value
    Ok(*total)

def main() -> Result[(), AllocError | IoError | OverflowError[i64]]:
    mut handlers = [Handler(10, accumulate), Handler(100, subtract)]?
    for handler in &mut handlers:
        print(handler.call(3)?)?
    print(handlers[0].call(2)?)?
    Ok(())
13
97
15

Each record owns its state; call borrows it exclusively. Constructing the records needs no allocation, but storing them in a list does.

For different state shapes, use an enum and handle its variants in the callback. Owned concrete closures can also be stored when their producer types agree.

See examples/callback_registry.plenty for a registry example.