Expand description
Β§π§© Variables, Let Bindings, and Scoping
Variables in Compose are introduced using the let keyword. Every variable has a scopeβthe region of code where it is visibleβand Compose is designed to make variable behavior clear and predictable.
Β§π Let Bindings
To bind a value to a name, use let:
let x = 10;
let name = "Compose";By default, variables are immutableβonce assigned, they cannot be changed:
let x = 5;
x = 6;error[E0004]: cannot reassign to a variable declared as immutable
ββ main.comp:2:1
β
1 β let x = 5;
β - was defined as immutable here
2 β x = 6;
β ^ is immutable
β
= note: variables are immutable by default
= help: make the variable mutable by writing `let mut`
= help: for more information about this error, try `compose explain E0004`If you want to change the value later, use let mut to make the variable mutable:
let mut count = 0;
count = count + 1;
assert::eq(count, 1);Compose encourages immutability for clarity, but allows mutation when itβs explicitly requested.
Β§π« Uninitialized Bindings
In Compose, you can declare a variable without giving it an initial value.
This can be useful when multiple branches assign different values to the same variable:
let x;
if (true) {
x = 1;
} else {
x = 2;
};
assert::eq(x, 1);However, in this instance we might use the fact that
ifis an expression to assign the intended value to x directly.let x = if (true) { 1; } else { 2; }; assert::eq(x, 1);
Reading an uninitialized variable is allowed and resolves to () (the unit value).
However, this produces a warning and relying on this behaviour should be avoided.
let x;
assert::eq(x, ());warning[W0001]: use of variable before it has been initialized
ββ main.comp:2:12
β
1 β let x;
β - variable declared here without an initial value
2 β assert::eq(x, ());
β ^ use of uninitialized variable
β
= note: uninitialised variables evaluate to `()` by default
= help: for more information about this error, try `compose explain W0001`Β§π Variable Scope
The scope of a variable starts where it is declared and ends at the closing brace of the block that contains it.
let outer = 10;
{
let inner = 20;
assert::eq(outer, 10);
assert::eq(inner, 20);
};
assert::eq(inner, 10); // inner is out of scope hereerror[E0011]: Unbound variable: `inner`
ββ main.comp:7:12
β
7 β assert::eq(inner, 10); // inner is out of scope here
β ^^^^^ this variable is unbound here
β
= help: for more information about this error, try `compose explain E0011`Variables can shadow earlier bindings in a new scope:
let value = 1;
{
let value = value + 1;
assert::eq(value, 2);
};
assert::eq(value, 1);Variables can also be shadowed in the same scope:
let x = 1;
let x = x + 1; // shadowing, not mutation
assert::eq(x, 2);Shadowing is a way to βreuseβ names safely. Each binding is separate and lives in its own scope.
Β§β Summary
- Variables are immutable by default. Use
let mutto allow mutation. - Use
letto bind values or patterns. - Variables can be uninitialised and resolve to
()before assignment. - Scoping rules help prevent accidental usage of invalid or stale values.
- Shadowing lets you reuse names in a controlled and explicit way.