Home Docs Download About Contact
Download

Memory safety

Ownership, borrowing, and why Prism programs don't have use-after-free.

Language Updated 2026-08-01 Edit this page

Prism is memory safe by default. The compiler proves, before your code runs, that no pointer outlives the data it points to, that nothing is read after it is freed, and that no two threads mutate the same value at the same time.

The system is ownership-based: every value has exactly one owner, and values move by default. If you have written Rust, the model is familiar; if not, this page is enough to get started.

Ownership

Every value has exactly one owner. When the owner goes out of scope, the value is dropped.

fn main() {
    let data = [1, 2, 3]   // `data` owns the array
    // ...                 // used here
}                          // and freed here, automatically

Passing collections

Arrays are passed by value — the callee works on its own copy:

fn total(nums: [int]) -> int {
    let mut sum = 0
    for n in nums { sum += n }
    return sum
}

fn main() {
    let data = [1, 2, 3]
    println(total(data))
}

The compiler enforces two rules:

  1. Every value has exactly one owner at a time.
  2. A value is never used after it has been moved.

Both are checked at compile time. There is no runtime cost.

Moving

Passing a value to a function moves it — ownership transfers:

fn consume(data: [int]) {
    println(len(data))
}

fn main() {
    let a = [1, 2, 3]
    consume(a)   // `a` is moved; using it after this is a compile error
}

The compiler tells you exactly where the move happened, so the error message reads like a conversation, not a verdict.

Unsafe, when you need it

Some problems — calling foreign functions, memory-mapped I/O, lock-free data structures — cannot be expressed with safe code alone. Prism provides unsafe blocks for those cases:

fn main() {
    let buf = arena_alloc(64)     // pointer builtins, gated behind unsafe
    println("ok")
}

Unsafe code is a deliberate, reviewable act, not an ambient property of the language. The compiler emits a warning on every unsafe block, and the standard library wraps almost all of them behind safe APIs.

Note: the exact pointer builtin names are defined in tests/test_pointer.prism — mirror those rather than inventing your own.

The result

A whole class of production incidents — use-after-free, double-free, data races, iterator invalidation — does not exist in safe Prism code. The remaining bugs are logic bugs, and those are easier to find because the crashes are reproducible.

Next: PrismX UI.