Constants

A constant is a name for a value the compiler computes once, before the program runs. It is declared with const, can never change, and can be used wherever the language needs a compile-time value — an array size, for instance.

constant = ["pub"] "const" Name [":" type] "=" expression ";"
const MaxConnections = 100;
const Ratio: float64 = 1.5;
const Greeting: char8[..] = "hello";

The type annotation is optional. Without one, the constant takes its initializer's type, exactly as a let would: MaxConnections above is an int. With one, an unsuffixed literal takes the annotated type, and must fit it — const Small: uint8 = 300; is error: integer literal is out of range for type 'uint8'.

By convention, constant names are PascalCase.

Where a constant may appear

PlaceExampleNamed as
A module, at top levelconst Limit: uint = 4;Limit
A function bodyconst Local = Limit * 2;Local
An extend blockconst Zero = Point { x: 0, y: 0 };Point::Zero

A module-level constant may be pub, like any other declaration — see Visibility. A constant declared in an extend block is an associated constant of the type, and is named through it:

extend Point {
    const Zero = Point { x: 0, y: 0 };
    const Dimensions: int = 2;
}
PrintLine("{} {}", Point::Zero.x, Point::Dimensions);

The primitive types carry associated constants of their own, such as int8::Min and float64::Epsilon, once their type is imported from Core — see Integers.

What the initializer may contain

The initializer is computed by the compiler, so everything in it must be known before the program runs. It may use:

const Limit: uint = 4;
const Area = Limit * Limit + 1;
const Mask = (1u32 << 4) - 1;
const Origin = Point { x: 0, y: 0 };
const Primes: int32[4] = [2, 3, 5, 7];
const Pair = (1, true);
const Favourite = Color::Green;
const Bytes = sizeof(Point) + alignof(Point);
const OnWindows = #target.os == OperatingSystem::Windows;

A function call and a variable hold run-time values, so neither may appear:

const FromCall = Seven();
const FromVariable = counter;
error: call to 'Seven' is not a compile-time value
  help: declare 'FromCall' with 'let' to compute it at run time
error: 'counter' is not a compile-time constant
  help: declare 'FromVariable' with 'let' to compute it at run time

The same is true of a parameter. When the value can only be known as the program runs, it belongs in a let.

Constants as compile-time integers

An integer constant is a compile-time integer wherever one is required. It can give an array its size and a repeated array literal its count, and another constant can be computed from it:

const Limit: uint = 4;
const Area = Limit * Limit + 1;

func Main() -> int {
    const Local = Area * 2;
    var flags: bool[Limit] = [false; Limit];
    let grid: int32[Local] = [0; Local];
    PrintLine("{} {}", flags.length, grid.length);
    return 0;
}

This prints 4 34. A let holding the same number could not do this: its value exists only at run time.

A constant cannot change

A constant is not a variable, and nothing can assign to it. MaxConnections = 5; is error: cannot modify constant 'MaxConnections'.

Constants are not patterns

In a match arm, a bare name always binds a new variable, so a constant's name cannot be used to compare against its value. Writing one is an error rather than a silent new binding:

error: pattern 'Limit' cannot bind a new variable because 'Limit' already names a constant
  help: a pattern compares with literal values; write the value of 'Limit', or bind the value and compare it with 'Limit' in a guard such as 'value if value >= Limit'

Compare in a guard instead:

match n {
    v if v == Limit => PrintLine("at the limit"),
    else => PrintLine("elsewhere")
}

const or let

constlet
Computedby the compiler, onceeach time the line runs
Initializercompile-time values onlyany expression
Module levelallowednot allowed
extend blockallowed, as Type::Namenot allowed
Array size, repeat countallowednot allowed

See also