This library is in flux. APIs may change without notice. Generated from source with koruc 0.1.7 on 8/19/2026.
Grid
~import std/gridKoru Standard Library: Grid — a fixed, positionally-addressed table
grid.kz · 3 tors
Koru Standard Library: Grid — a fixed, positionally-addressed table · 45 more lines
Koru Standard Library: Grid — a fixed, positionally-addressed table
A grid is the OTHER kind of table, and the distinction is one question:
CAN A ROW MOVE?
std/store — yes. `take` swap-removes, so position is not identity, so a
row is named by a generational HANDLE and every access pays a
brand + bounds + generation check. The store earns that
machinery by supporting removal.
std/grid — no. Every cell exists from declaration and none is ever
inserted, removed or relocated, so POSITION IS IDENTITY. A
grid pays nothing: no handles, no generation word, no sparse
indirection, no freelist, no `len`.
A grid is therefore the degenerate, fastest table in the language, and it
gets there by forbidding something rather than by optimising.
USAGE:
import std/grid
std/grid:new(cells, size: 4096) { count: 0[i64], sx: 0.0[f32] }
std/grid:stored { cells[h].count: cells[h].count + 1 }
SIZE, not capacity. `capacity: N` means "up to N, currently `len`". A grid
is EXACTLY N cells, all live from the moment it is declared. Different
contract, different word, so the two declarations cannot be misread.
OUT OF RANGE TRAPS (ruled 2026-08-03). An index outside `0..size` is a
panic naming the grid, matching the store's stale-handle floor: fail loud,
never silently address a neighbour. Wrapping is the PROGRAM's decision and
belongs in the source as an explicit `% size` where a reader can see it — a
spatial hash wants exactly that and should say so.
The check is a floor, not a tax to be paid forever: an index the compiler
can prove in range needs none, and a `! sweep` arm over a grid is precisely
that case — the loop constructs the index from `0..size`, so validating it
would be validating a fact established one line above. That is the same
floor-then-prove-away arc the store's handle check follows.
NOT REACTIVE, deliberately, and the seam is left open. Nothing about a grid
forbids watches or interceptors — reactivity in Koru is spliced at comptime
and costs nothing when nobody listens. But every reactive surface has to
answer what it FIRES, and a whole-grid clear firing four thousand times is a
question no workload has asked yet. It gets designed when one does.
// GRID.NEW — declare a fixed, positionally-addressed table
~[keyword|comptime|transform] pub tor new {
expr: Expression,
source: Source,
invocation: *const Invocation,
item: *const Item,
program: *const Program,
reporter: std/compiler:*ErrorReporter,
allocator: std.mem.Allocator
} -> SiteResult// GRID.STORED — positional write, and positional reads in the values
//
// std/grid:stored { cells[h].count: cells[h].count + 1 }
//
// There is no write EVENT and no envelope. The store routes every write through
// one centralizing subflow because that is where reactivity splices; a grid has
// nothing to splice, so a write is a write and lowers to an assignment.
~[keyword|comptime|transform] pub tor stored {
source: Source,
invocation: *const Invocation,
item: *const Item,
program: *const Program,
reporter: std/compiler:*ErrorReporter,
allocator: std.mem.Allocator
} -> SiteResult// GRID.SWEEP — visit every cell
//
// std/grid:sweep(cells)
// ! sweep c when c.count > 0 |> std/store:stored { acc.n: acc.n + 1 }
//
// NO BOUNDS CHECK. The loop constructs the index from `0..size`, so validating
// it would be re-establishing a fact from one line above — the same
// floor-then-prove-away arc the store's handle check follows, and the reason the
// grid's trap is a floor rather than a tax.
//
// This lowers to an ordinary `for(0..size) ! each <i>`, with every `c.<field>`
// in the body rewritten to a direct cell read. It mints no event and transplants
// no body: `for` already knows how to inline effect handlers, so reusing it
// keeps the body Koru all the way down — a nested `std/store:stored`, a
// `print.ln`, a guard, all behave exactly as they do anywhere else, because
// nothing about them has been moved.
~[keyword|comptime|transform|claims_descendants] pub tor sweep {
expr: Expression,
invocation: *const Invocation,
item: *const Item,
program: *const Program,
reporter: std/compiler:*ErrorReporter,
allocator: std.mem.Allocator
} -> SiteResult