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:
- Binding — How a name is tied to a value (
::vs:=). - Constness — Whether data can be changed (
const). - Representation — Where it lives (Stack, Heap, Rodata).
- 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
| Syntax | Segment | Owner | Lifetime | Notes |
|---|---|---|---|---|
:: [N; T] | .rodata | Binary | Global | Immutable, baked into binary |
:= [N; T] | Stack | Scope | Local | Cleared on function return |
:= alloc(T, n) | Heap | Perceus | Managed | Automatic RC; freed when ref drops |
[]T | Slice/View | Argus | Scope-bound | Points into an allocation; no ownership |
*T | Escapee/Raw | Argus | Scope-confined | Untracked, 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 Tslices:view[0] <- 42— compile error.:: [N; T]values: Rodata is immutable — compile error.
5. Cheat Sheet
| Syntax | Type | Memory | Owner | <- | := | Escapes? |
|---|---|---|---|---|---|---|
x :: [N; T] | Constant | Rodata | Binary | No | No | Yes |
x := [N; T] | Local buffer | Stack | Scope | Yes | Yes | No |
x := [*]T | Tracked ptr | Heap | Perceus | Yes | Yes (FBIP) | Yes |
x := Vec[T] | Growable | Heap | Perceus | Yes | Yes | Yes |
x : []T | Mutable view | View | Argus | Yes | No | If Rodata/Heap |
x : *T | Escapee | Raw | Argus | Yes | No | No |
6. Summary
::is compile-time;:=is runtime binding.:=updates an existing cell (no shadowing).- FBIP/COW ensures value semantics for heap rebindings.
<-mutates memory at a location; RC is irrelevant here.- Argus enforces safety at compile-time; no runtime checks or lifetime annotations required.