Variables
Tao is intentionally strict about names: variables are immutable unless declared mutable, and every name may be defined exactly once in its scope.
let
let declares an immutable binding.
let x = 42
x = 10 // error: cannot assign to immutable variable
let mut
let mut declares a mutable binding that can be reassigned.
let mut x = 5
x = 10 // ok
const
const declares a top-level constant. Like let, it is immutable.
const LIMIT = 100
Destructuring
let a, b = expr unpacks the first two elements of a list into two immutable
variables. Extra elements are ignored.
let val, err = readFile("x") // val = first, err = second
The right-hand side must be a list with at least two elements, or the program stops with a runtime error.
Assignment
The right of = may be an identifier, a field access, or an index. Assigning
to anything else is an error.
x = 2 // variable
p.y = 1 // field
xs[0] = 42 // element
Names are defined once
Redefining a name in the same scope is an error, whether it is a variable, a function, or a type.
let x = 1
let x = 2 // error: already defined variable: x
Scopes
Each block opens a new scope. Inner blocks can read outer variables, and closures capture the scope where they were created.
fun f() {
let mut n = 0
let c = fun -> () { n = n + 1; n }
c()
c() // 2
}
f()
Because bindings are immutable unless declared mut, a closure can only
update state captured as let mut.