Variables & Scope
Variables don't need to be declared; assigning to a new name creates it.
foo = 5
foo = foo + 1
Variables don't have fixed types, either – a variable can go from holding a number to holding a string.
bar = 17
bar = "hello, world"
Where assignments land
Assignment x = ... modifies an existing variable within the current function, if there is one. Otherwise it creates a new variable in the nearest { ... } brackets:
{
x = 1
{ x = 2, y = 3 }
show x # x = 2
show y # Error: `y` is not defined
}
Here the inner x = 2 updates the outer x, because one already exists. But y is created fresh in the inner block, and doesn't exist outside it.
This rule means variables can't "leak" out of conditionals in a way that depends on runtime values. If you want to initialise a variable inside an if or a loop, give it a value first:
x = nil
if condition {
x = 2
}
Now x is defined either way.
Functions are boundaries
A function can never alter a variable outside its own body. It's free to use an outer name, but assigning to it creates a fresh, local variable:
x = 1
fn foo() {
x = 2
show x
}
foo() # x = 2
show x # x = 1
If you actually want a function to change a caller's variable, that's what swap arguments are for.
let
let overrides the default and creates a new variable, regardless of whether one already exists. The new variable shadows the old one for the duration of the let block:
{
x = 1
let x = 2 { show x } # x = 2
show x # x = 1
}
let is also the entry point to pattern matching in conditionals – if let Some(x) = m { ... } – which we'll come to later.