Skip to main content

Variables & Scope

Variable names can contain letters or numbers, but must start with a letter. By convention multi-word names are written in camelCase.

foo
bar3
myLongVariableName
i18n

New variables don't have to be declared specially. Assigning to an unused variable name will create that variable.

foo = 5
foo = foo + 1

It's possible to assign to any variable at essentially any point, but the exact behaviour depends on the surrounding context – assignment to foo might update foo, or create a new variable with the name foo.

Function scopes

Functions cannot alter a variable outside of the function body. For example

x = 1

fn foo() {
x = 2
}

foo()
println(x) # => 1

foo is free to create and use a variable called x, but it is a new variable unrelated to the x in global scope. The same applies to closures.

Control flow scopes

Variables assigned inside a while, for or if/else will update an outside variable if it exists.

fn foo() {
x = 1
if true {
x = 2
}
return x
}

println(foo()) # => 2

However, if there is no outer variable with the same name, the variable only exists inside the if body.

fn foo() {
if true {
x = 2
}
return x
}

println(foo()) # => error: No variable named `x`

If this code were to work, it would nevertheless break if the if condition were false. Preventing variables from "leaking" in this case simplifies things: a variable is either defined or it isn't, regardless of any runtime values.

If you need to initialise a variable inside a loop or conditional, just set it to nil first.

fn foo() {
x = nil
if true {
x = 2
}
return x
}

println(foo()) # => 2

Let scope

let allows you to create a new variable regardless of whether one already exists.

fn foo() {
x = 1
let x = 2 {
# ...
}
return x
}

println(foo()) # => 1

Inside the let body, assignments work the same as in loops and conditionals.