Learn
Ownership tiers
Most languages pick one memory model for everything. Grasm gives four and lets the value decide, so the common case stays simple and the hard case stays possible.
| Tier | What it is | Costs |
|---|---|---|
| 0 — borrow | The default. A parameter borrows; the caller keeps the value. | Nothing. |
1 — region | A scope nothing allocated inside may outlive. | Nothing at the boundary; the guarantee is checked. |
2 — ref T | A generational reference into a shared heap. Copies freely, stores in a struct, forms cycles. | One allocation; a generation check on use. |
3 — unsafe | The explicit escape, and an effect in the row. | You are on your own, and the type says so. |
Tier 2 in practice
let counter = ref(0)
counter.value += 1
let same = counter // a reference is a word: it copies
same.value += 1
print("{counter.value}") // 2 — both name one slot
release(counter) // the slot goes back
print("{alive(counter)}") // false, through every copy of it
Reclamation is manual. A slot returns to the pool when it is released and not before — which is the point of the tier: the lifetime is the program's to state. Releasing twice is not an error, so cleanup order is not something every caller has to track.
Tier 1 in practice
let n = region {
let scratch = build_a_big_thing()
scratch.len() // a scalar may leave; an allocation may not
}
Three rules give the guarantee: a region may not write to a binding declared
outside it, may not return through its brace, and yields a scalar
or nothing. The rule is enforced today; the bulk deallocation it exists to make
sound is not yet implemented, and the specification says so rather than
implying otherwise.