Allocation

Stack allocation

Local variables, fixed-size arrays, array literals and structs live on the stack:

tape
fn compute() {
    var buffer: [1024]u8;                         // stack-allocated (zeroed)
    let items = [1, 2, 3, 4, 5];                  // stack-allocated
    var point: Vec2;                              // stack-allocated (zeroed struct)
    let p = Person { name: "Alice"; age: 30; };   // stack-allocated
}

Stack space is reserved in the function prologue. No allocation call is needed. A struct is plain bytes held inline wherever it is stored (a local, a field, an array element); returning one copies it to the caller.

Heap allocation

Component instances are heap-allocated:

tape
let app = Counter {};                         // heap-allocated (component)

The managed parts of a value (a computed string’s buffer, a container’s elements) live on the heap too, owned by the value; see Ownership.

The mem module

For manual heap allocation, import the mem module:

tape
import mem from "mem";

let data: *u8 = mem.alloc(size) or return;   // MemError.OutOfMemory passes on
defer mem.free(data, size);
FunctionSignatureDescription
alloc(size: i64) -> *u8 or MemErrorAllocate bytes (zeroed); MemError.OutOfMemory when there is no memory
alloc_or_trap(size: i64) -> *u8The same, stopping the program with trap: out of memory instead
realloc(p: *u8, old: i64, new: i64) -> *u8 or MemErrorResize a block (contents kept, p freed)
free(ptr: *u8, size: i64)Free allocation
heap_arena / free_arena(size: i64) -> arena.Arena or MemError / (a: *arena.Arena)An arena over heap memory
copy_raw, move_raw, set_raw, zero_raw(dst: *u8, src: *const u8, n: i64), …The byte operations below with i64 lengths
copy(dst: *u8, src: *u8, count: u64)Copy bytes (non-overlapping)
move(dst: *u8, src: *u8, count: u64)Copy bytes (overlapping safe)
set(dst: *u8, val: u8, count: u64)Fill memory with byte value
zero(dst: *u8, count: u64)Zero-fill memory
compare(a: *u8, b: *u8, count: u64) -> i32Compare bytes (-1, 0, 1)
equal(a: *u8, b: *u8, count: u64) -> boolByte equality check
live_allocs() -> i64Heap blocks currently allocated (strings included)

Note: mem.free takes the pointer and the block’s size; the size is a hint the runtime may ignore (pass 0 when you don’t know it). See mem.

String allocation

The string type is a 24-byte descriptor (pointer + length + capacity). String operations that produce new values (+, interpolation) heap-allocate internally. The compiler manages string lifetime automatically — see Ownership.

tape
let greeting: string = "Hello, " + name;  // heap-allocated result
// freed automatically at scope exit

Where values live

ValueLocation
Primitives (i64, bool, f64, etc.)Stack (local slot)
Fixed arrays ([N]T)Stack
Array literals ([1, 2, 3])Stack
Struct locals and literals (Type { ... })Stack (inline)
Component instances (Comp {})Heap
Strings (dynamic)Heap (descriptor on stack, data on heap)
mem.alloc(...)Heap
SlicesStack (fat pointer: ptr + len)

Last modified: