Bindings and scope
let introduces a new binding. Assignment changes an existing binding.
let count = 0count = count + 1print(count) # 1There is no mut modifier. Bindings created with let can be reassigned, and const is not implemented.
Annotated initialization
Section titled “Annotated initialization”let count: Int = 3let label: Str = "ready"The interpreter checks each initializer against its annotation. In the current implementation, the annotation is then discarded: it does not prevent subsequent assignment of a different type. Treat it as an assertion about initialization, not a persistent binding contract. Function parameters, function returns, and kind fields have their own runtime checks.
Lexical scope
Section titled “Lexical scope”A name is visible in its defining scope and nested scopes.
let label = "outside"with { let label = "inside" print(label)}print(label)This prints inside, then outside. The inner let shadows the outer name. By contrast, an assignment without let searches for and updates an existing binding:
let total = 1with { total = total + 4}print(total) # 5The difference matters for closures: reassignment changes the binding a closure already captured; a new let creates a new binding.
Tuple destructuring
Section titled “Tuple destructuring”let (name, score) = ("Ada", 42)let (_, (x, y)) = ("point", (3, 4))print("{name}: {score}")print(x + y)A tuple pattern names its parts, and _ discards a part. Patterns can nest. A binding name cannot appear twice in the same pattern.
let accepts irrefutable patterns: bindings, wildcards, and tuples of those patterns. Use match when a pattern might not fit, such as an enum variant or a literal.
Do not read let second = first as a promise of deep copying. Collection aliases currently share backing storage in ways that can become invalid after growth; see collections.