Skip to content

Values

Copying, sharing, cloning, mutation, equality, destruction, and managed storage.

Updated View as Markdown

Atoll source is value-oriented. Programs construct and pass values without choosing stack addresses, heap allocators, boxes, or reference-count operations.

point := Point { x: 3, y: 4 }
other := point

The compiler selects an inline, managed, borrowed, or boxed representation that preserves the type’s source semantics.

Scalars

Primitive scalars and all-scalar aggregates copy their value lanes.

struct Point {
    x: int
    y: int
}

first := Point { x: 3, y: 4 }
mut second := first
second.x = 10

Updating second.x does not update first.x. There is no hidden shared Point object required by the source type.

Tuples and enum payloads follow the same field-wise representation rule.

Managed values

Strings, lists, maps, sets, closures, recursive values, and aggregates containing managed fields can own arena-backed storage.

Copying such a value can share that storage and adjust compiler-managed reference counts instead of deep-copying every byte.

first := "a long value"
second := first

The source program does not write retain or release operations. The compiler inserts, moves, cancels, and verifies them.

Cloning

Use clone() when an independent owned copy is required.

independent := original.clone()

The exact cost depends on the type. For a collection or string, cloning can allocate and copy backing content. For an all-scalar value it can collapse to a simple value copy.

Do not use clone() reflexively to satisfy the compiler. Ordinary passing and binding already preserve the source contract, and the optimizer can borrow or move where safe.

Collections

List, map, and set copies may share backing storage. Mutating operations use the collection’s defined aliasing and growth rules.

Current list behavior distinguishes element updates from growth:

  • views or holders of the same backing block can observe in-range element updates made through an allowed mutable path;
  • a grow may reseat the growing owner to different storage;
  • an existing slice remains a view of the storage/range it already pins;
  • clone() creates an independent collection.

Use explicit clones when independent mutation is part of the program’s meaning.

Mutation

Mutability is a source permission, not a storage class.

mut count := 0
count += 1

A field or indexed place can be updated only through a mutable path and a type operation that permits the write.

mut point := Point { x: 0, y: 0 }
point.x = 1

mut self and mutable parameters state that a callee may update through its receiver or argument. They do not expose the compiler’s allocation choice.

Borrowing

The compiler can pass a read-only value without copying or incrementing a reference count when interprocedural analysis proves the callee does not retain it.

fn title(report: Report): string {
    return report.title
}

This implicit borrow is an optimization that preserves value semantics. Source code does not become invalid merely because an optimizer chooses a different legal borrow/move plan.

Explicit identity-preserving references use &T and are covered in References.

Equality

== and != use value equality. Primitive values have direct behavior; user-defined values participate through Equatable.

same := first == second

Do not infer identity from a WebAssembly handle or arena offset. Those are representation details and can change across compiler versions or specializations.

Hashable values must keep equality and hash_code() consistent.

Destruction

When a value’s ownership ends, the compiler releases its managed fields. Reference-counted storage is reclaimed when its final owner or pin leaves.

The compiler handles normal exits, branches, early returns, error propagation, and resumable frames. It also removes redundant retain/release pairs where proof permits.

A type implementing Drop receives its user-defined finalization at the compiler-defined destruction point. Drop is for resource semantics, not for manual memory deallocation.

Cycles

Reference counting alone cannot reclaim a strongly connected cycle. The runtime and compiler track cycle-capable managed types separately from provably acyclic values.

Weak fields can break ownership cycles when the relationship is semantically non-owning. See References.

Representation

Inline lanes, arena blocks, frame slots, closure environments, RC headers, and WebAssembly ABI lanes are compiler/runtime contracts. They belong in the MIR and Runtime sections, not in application type annotations.

The language guarantees typed values, explicit mutation permissions, value-defined equality, safe lifetimes, and deterministic source-visible cleanup—not one permanent byte layout for every type.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close