Variables
Variables are storage locations identified by name.
Bindings
binding = "let" [ "mut" ] pattern [ ":" type ] "=" expression .
assignment = identifier "=" expression .
A let binding introduces an identifier into the current scope. Bindings are immutable by default.
let x = 42
let name: str = "Alice"
let mut counter = 0
Type annotations are optional; types are inferred when omitted. Annotated type must match inferred type.
Mutability
Mutable bindings use mut modifier:
let mut x = 0
x = x + 1 // OK
let y = 10
y = 20 // error: immutable binding
Cannot reassign:
- Immutable bindings
- Function parameters
- Config variables
Scope
Bindings are visible from declaration to end of enclosing block.
run(
let x = 10,
let y = x + 5, // x visible
y,
)
// x, y not visible
Shadowing
Bindings may shadow earlier bindings with the same name:
run(
let x = 10,
let x = x + 5, // shadows, now 15
x,
)
Destructuring
pattern = identifier
| "_"
| "{" field_pattern { "," field_pattern } "}"
| "(" pattern { "," pattern } ")"
| "[" pattern { "," pattern } [ ".." identifier ] "]" .
Patterns destructure composite values:
let { x, y } = point
let { x: px, y: py } = point // rename
let (a, b) = pair
let [head, ..tail] = list
let { position: { x, y } } = entity // nested
Pattern must match value structure.
Function Parameters
Parameters are immutable bindings scoped to the function body:
@add (a: int, b: int) -> int = a + b