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).
| 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. |
// 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
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
// 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 StorageGlobal 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