2. Variables and Constants
2.1 Immutable Bindings (let)
let x = 42;
let pi = 3.14159;
let name = "Alice";
-- Optional type annotation (type follows name)
let typed_var Int = 100;
2.2 Mutable Variables (var)
var counter = 0;
var message = "hello";
-- Can be reassigned
counter = counter + 1;
message = "goodbye";
2.3 Constants (const)
const MAX_SIZE = 1000;
const TAU = 6.28318;
2.4 Dynamic Scope Variables
Dynamic scope variables are looked up in the dynamic call chain rather than
the lexical scope. They are declared with var and a backtick-prefixed name.
This is useful for implicit context that should propagate through function calls
without being passed explicitly.
-- Declare a dynamic variable at global scope
var `indent = 0;
-- Read and assign like a regular mutable variable
println(`indent); -- 0
`indent = 5;
println(`indent); -- 5
`indent = `indent + 10;
println(`indent); -- 15
Dynamic variables are visible to all functions called from the current scope:
fn showIndent() {
println(`indent); -- reads the caller's `indent
}
showIndent(); -- 15
Re-declaring a dynamic variable inside a function saves the current value and sets a new one. When the function returns, the previous value is automatically restored:
fn nested() {
var `indent = 100; -- saves old value, sets to 100
showIndent(); -- 100
`indent = 200;
showIndent(); -- 200
}
nested();
println(`indent); -- 15 (restored after nested() returns)
Save/restore nests to any depth:
fn outer() {
var `indent = 1000;
fn inner() {
var `indent = 2000;
showIndent(); -- 2000
}
inner();
showIndent(); -- 1000 (inner's binding was restored)
}
outer();
showIndent(); -- 15 (outer's binding was restored)
Dynamic variables can be any type:
var `prefix = ">>>";
fn showPrefix() { println(`prefix); }
showPrefix(); -- >>>
fn withPrefix() {
var `prefix = "***";
showPrefix(); -- ***
}
withPrefix();
showPrefix(); -- >>> (restored)