Verbs
A mutating verb takes its outputs first, as a NamedTuple it destructures — f!((; Y), X; kws...) — and describes them with outputs. Its Allocating form is the same verb with the first argument answering where results live instead of which arrays: a Space the outputs materialize from, before any frame opens.
Pol.Allocating — Type
Allocating(f!)The allocating form of a mutating verb: a callable that owns the outputs/scratch ritual so call sites don't repeat it.
const decode_attention = Allocating(decode_attention!)
o = decode_attention(space, q, K, V; lengths)The first argument answers where results live — the mutating verb takes its output buffers there, the allocating form takes a Space to materialize them from. Calling it allocates outputs from space — before any frame opens, so on an Arena they sit below the frame's mark and survive its retract — then runs f! and returns the outputs NamedTuple. A verb marked @takes_space runs inside a scratchspace block and receives the frame as its space keyword: its defaulted scratch is carved there and reclaimed at return.
space may itself be a Frame — frames are spaces and nest — in which case the outputs take the caller's frame lifetime.
The output_override keyword merges caller-owned arrays over the outputs spec before materialization, so an overridden entry is never allocated — pass the verb's own state array to run partially in place: f(space, args..., S; output_override = (; S′ = S)).
Pol.takes_space — Function
takes_space(f!) -> BoolWhether the mutating verb f! accepts a space keyword — the space its defaulted scratch materializes from. false generically; declare with @takes_space. Allocating branches on it: a verb that takes no space is called bare, with no frame opened on its behalf.
Pol.@takes_space — Macro
Pol.@takes_space f!Declare that the mutating verb f! accepts a space keyword (see takes_space). One line next to the verb's scratch method:
Pol.@takes_space decode_attention!