burn / docs

Language

Variables, constants and scope

Declaring variables

A variable is declared in one of three ways. All three mean the same thing; pick the one that reads best.

var count = 0              // the type comes from the value: int
var ratio: float = 1       // the type after the name
string name = "Burn"       // the type first, like in Java or C
[int] ids = [3, 5]
  • With var and no type, the variable gets the type of its value. var x = null is an error ("cannot infer the type of x from null"); write the type, string? x = null.
  • Built-in type names can be written lower or upper case: int/Int, float/Float, string/String, bool/Bool, any/Any.
  • A variable keeps its type. var x = 1 followed by x = "one" is an error ("expected int but found string"); declare it as any x = 1 when it should hold different kinds of values.

Zero values

A variable declared without a value starts with the zero value of its type:

var a: int
string s
[int] xs
{string: int} m
int? n
float f
bool b
print(a, "[" + s + "]", xs, m, n, f, b)

This prints 0 [] [] {} null 0.0 false.

Type Zero value
int, sized integers 0
float, float32 0.0
bool false
string ""
[T] an empty array
{K: V} an empty map
T?, any null
an enum without data its first variant

Structs, records, functions and enums with data have no zero value, so a variable of such a type needs one: Point p is an error ("p of type Point must be initialized").

Constants

const declares a name that cannot be assigned again:

const LIMIT = 10
const float RATE = 0.5
const NAMES = ["ada", "lin"]

fun main() {
    const local = LIMIT * 2
    NAMES.push("grace")
    print(local, NAMES)
}
  • A constant can be declared at the top level, in a function, or as a static const in a struct.
  • Its value can be any expression, including a function call; it is computed once, when the line runs.
  • const protects the name, not the value: NAMES = [] is an error, but NAMES.push(...) changes the array the constant holds.
  • Assigning to a constant is an error: "cannot assign to constant LIMIT".

Scope

A name is visible from its declaration to the end of the block ({ ... }) it is declared in.

var x = 1
if (x > 0) {
    var x = 2       // a new `x` inside this block
    var y = 3
    print(x, y)
}
print(x)            // 1; `y` is not visible here
  • A block can declare a name that already exists outside it. The inner name hides the outer one until the block ends. The same goes for a local variable with the name of a parameter.
  • Declaring the same name twice in the same block is an error ("x is already defined on line 1").
  • The variables of a for loop (for i in ..., for (var i = 0; ...)) only exist inside the loop.
  • Each iteration of a loop has its own copy of the variables declared in the loop body, so a closure created in one iteration keeps that iteration's values.
  • Functions, types and structs declared at the top level can be used before the line that declares them. Variables cannot.

Globals

Variables declared at the top level of a file are globals: every function in the file can read and change them.

var calls = 0

fun track() {
    calls += 1
}

track()
track()
print(calls)
  • Top level statements run from top to bottom when the program starts (or when the module is first imported). A program with a main function runs main after them.
  • A global can only be read after its line has run. The compiler checks this, also through function calls: calling a function that reads count before var count = ... has run is an error that names the function. See what the compiler guarantees.
  • priv var keeps a global inside its module; other globals can be read and assigned by modules that import it (see modules).
  • Async tasks share globals with the rest of the program. Do not change the same global from several tasks at once.

Assignment

= assigns a new value, and +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= and >>>= combine an operator with the assignment. The left side can be a variable, a field (p.x = 3), an array element (xs[0] = 1) or a map entry (ages["ada"] = 37).

var s = "ab"
s += 1
var n = 7
n /= 2
n %= 2
print(s, n)

An assignment is also an expression whose value is the assigned value, so a = b = 0 sets both. There is no ++ or --; write i += 1.