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

Ore Ownership & Memory Model

Ore’s memory and ownership system is simple, predictable, and orthogonal. Memory and operations are defined across four independent layers. Together, they dictate how names, memory, and mutation behave.

The Four Layers of Ore Memory:

  1. Binding — How a name is tied to a value (:: vs :=).
  2. Constness — Whether data can be changed (const).
  3. Representation — Where it lives (Stack, Heap, Rodata).
  4. Addressability — How you access it (Direct, Slice, Pointer).

1. Bindings: :: vs :=

:: — compile-time constant: Creates a name bound at compile time. Usually stored in .rodata or .data. Immutable and shared across calls.

:= — runtime binding: Binds a name to a value at runtime. The value may reside on stack or heap depending on type. Always rebindable; := does not mutate existing memory.

digits :: [10; u8].{0,1,2,3,4,5,6,7,8,9}  // compile-time, shared
x := [3; u8].{10,20,30}                    // stack-allocated, local
matrix := [2; [3; u8]].{
	.{1,2,3},
	.{4,5,6}
}                                          // nested fixed array, still stack-allocated

Nested fixed arrays stay in the fixed-array family. [2; [3; T]] is still a stack or rodata value, depending on whether it is introduced with := or ::.

Note: In Ore, a variable name is a fixed “slot.” Rebinding with := changes what’s in the slot; it does not create a new slot with the same name (no shadowing).

2. Memory Representation

SyntaxSegmentOwnerLifetimeNotes
:: [N; T].rodataBinaryGlobalImmutable, baked into binary
:= [N; T]StackScopeLocalCleared on function return
:= alloc(T, n)HeapPerceusManagedAutomatic RC; freed when ref drops
[]TSlice/ViewArgusScope-boundPoints into an allocation; no ownership
*TEscapee/RawArgusScope-confinedUntracked, cannot escape scope
  • Perceus: Automatic Memory Manager / Reference Counting.
  • Argus: Compile-time Safety / Escape Checker.

3. Ownership & Lifetime

3.1 Allocation-level ownership

  • Stack [N; T] — scope-owned; freed automatically.
  • Heap [*]T / Vec[T] — Perceus-managed; reference-counted.
  • Rodata :: [N; T] — immutable; lifetime tied to the binary.

3.2 Views & slices

  • []T — mutable view; cannot escape unless backing storage is Rodata or heap.
  • []const T — immutable view.

Slices do not increment RC. Mutating through a slice affects all aliases of the underlying allocation. A sub-slice (s2 := s1[1..3]) inherits the scope of the original allocation, not the intermediate slice — this prevents “scope laundering” through chains of sub-slices.

3.3 Who can leave the function?

  • Owners ([*]T, Vec[T]) — can escape any scope; returning one moves ownership to the caller.
  • Views ([]T, *T) — confined to the scope of backing storage. Argus enforces this at compile time.

4. Operations: := vs <-

4.1 Binding and Rebinding (:=)

:= creates or updates a ref cell. Rebinding an existing name updates the same cell (Koka-style x.set(value)).

When rebinding a heap allocation ([*]T):

  • FBIP (Functional But In Place): Reuses memory if RC=1.
  • COW (Copy on Write): If RC>1, a copy is made to preserve value semantics.

4.2 Memory mutation (<-)

Mutates addressable locations (elements, fields, dereferenced pointers). Operates directly on memory; never changes ownership or RC.

Mutation is not allowed on:

  • Bare bindings: x <- 20 — compile error. Use := to rebind.
  • []const T slices: view[0] <- 42 — compile error.
  • :: [N; T] values: Rodata is immutable — compile error.

5. Cheat Sheet

SyntaxTypeMemoryOwner<-:=Escapes?
x :: [N; T]ConstantRodataBinaryNoNoYes
x := [N; T]Local bufferStackScopeYesYesNo
x := [*]TTracked ptrHeapPerceusYesYes (FBIP)Yes
x := Vec[T]GrowableHeapPerceusYesYesYes
x : []TMutable viewViewArgusYesNoIf Rodata/Heap
x : *TEscapeeRawArgusYesNoNo

6. Summary

  1. :: is compile-time; := is runtime binding.
  2. := updates an existing cell (no shadowing).
  3. FBIP/COW ensures value semantics for heap rebindings.
  4. <- mutates memory at a location; RC is irrelevant here.
  5. Argus enforces safety at compile-time; no runtime checks or lifetime annotations required.