Mutability & Bindings

Zith uses deep mutability: the modifier on a binding propagates into all nested fields. Fields inside a struct are auto by default — they follow the mutability of the containing instance.

⚠ Important: Bindings only control reassignability. Content mutability is controlled via memory modifiers on the type (see Memory Model — NRA).

Binding Keywords

Keyword Controls Semantics
let Binding Immutable. Cannot be reassigned.
var Binding Mutable. Can be reassigned.
global Binding Static storage duration.
const Both Compile-time constant. Binding and content frozen.
comptime Both Mutable during compilation (e.g. compile-time counter), frozen at runtime.

Examples

// let — immutable binding
let x: i32 = 10;
// x = 20;                          -- COMPILE ERROR: let binding cannot be reassigned

// var — mutable binding
var y: i32 = 10;
y = 20;                              // OK

// const — compile-time constant
const PI = 3.14159;

// comptime — mutable at compile time, frozen at runtime
comptime COUNT = 0;
comptime COUNT += 1;                 // valid at compile time only
// @println(COUNT);                 -- frozen at runtime

Deep Mutability

In Zith, mutability is deep: a let binding means the entire value and all its fields are immutably bound. A var binding means the entire value and all its fields can be mutated.

struct Point { [x, y]: f32 }

let pt = Point { x: 1.0, y: 2.0 };
// pt.x = 3.0;                     -- COMPILE ERROR: pt is immutable

var pt2 = Point { x: 1.0, y: 2.0 };
pt2.x = 3.0;                        // OK: var binding, deep mutability

To control mutability at a finer grain, use var at the binding for mutable access, and let to prevent reassignment:

let pt = Point { x: 1.0, y: 2.0 };              // immutable binding, no mutations
var pt2 = Point { x: 1.0, y: 2.0 };             // mutable binding, deep mutation allowed

Destructuring

// Grouped destructuring — same type, related semantics
let [x, y, z]: f32;

// Individual — unrelated
let name: string;
let age: i32;

// Destructure in a for loop with fallback
let r = for ([acc, i]: i32), (i in 0..n) {
            acc *= i + 1
        } or 0;

global — Static Storage

Global variables have static storage duration and must satisfy thread-safety requirements through the Share or Lent capability:

global counter: share i32 = 0;          // requires Share capability
global config: unique Config = load();  // requires Lent capability (atomic access)

See also: Spec: Mutability & Bindings


Next: Functions