12 Constants
Constants are immutable bindings declared with the $ prefix.
Grammar: See grammar.ebnf § DECLARATIONS (constant_decl), CONSTANT EXPRESSIONS
12.1 Immutable Bindings
A binding prefixed with $ is immutable — it cannot be reassigned after initialization.
let $timeout = 30s;
let $api_base = "https://api.example.com";
let $max_retries = 3;
pub let $default_limit = 100;
The $ prefix appears at definition, import, and usage sites:
// Definition
let $timeout = 30s;
// Usage
retry(op: fetch(url), attempts: $max_retries, timeout: $timeout);
12.2 Module-Level Constants
All module-level bindings shall be immutable. Mutable state is not permitted at module scope.
let $timeout = 30s; // OK: immutable
pub let $api_base = "https://..."; // OK: public, immutable
let counter = 0; // error: module-level bindings must be immutable
Module-level constant initializers shall be pure expressions: they shall not use capabilities (uses), perform I/O, access mutable state, or reference non-constant bindings. This ensures deterministic initialization regardless of module load order.
let $a = 5; // OK: literal
let $b = $a * 2; // OK: constant expression
let $c = $square(x: 10); // OK: const function call
let $d = Clock.now(); // error: uses Clock capability
let $e = read_file("cfg"); // error: uses FileSystem capability
The compiler evaluates constant expressions at compile time when possible. Pure expressions that cannot be fully evaluated at compile time (e.g., those calling non-const functions) produce runtime immutable bindings that are initialized once when the module is first loaded.
12.3 Local Immutable Bindings
The $ prefix may be used in local scope to create immutable local bindings:
@process (input: int) -> int = {
let $base = expensive_calculation(input);
// ... $base cannot be reassigned ...
$base * 2
}
12.4 Identifier Rules
The $ prefix is a modifier on the identifier, not part of the name. A binding for $x and a binding for x refer to the same name — they cannot coexist in the same scope.
let x = 5;
let $x = 10; // error: 'x' is already defined in this scope
The $ shall match between definition and usage:
let $timeout = 30s;
$timeout // OK
timeout // error: undefined variable 'timeout'
12.5 Const Functions
A const function is a pure function bound to an immutable name. Const functions may be evaluated at compile time when all arguments are constant.
let $square = (x: int) -> int = x * x;
let $factorial = (n: int) -> int =
if n <= 1 then 1 else n * $factorial(n: n - 1);
// Evaluated at compile time
let $fact_10 = $factorial(n: 10); // 3628800
Const functions shall be pure:
- No capabilities (
usesclause) - No side effects
- No mutable state access
If called with non-constant arguments, the call is evaluated at runtime.
12.6 Constant Expressions
A constant expression is an expression whose value can be determined at compile time. The following are constant expressions:
- Literals: integer, float, string, character, boolean, duration, size
- References to
$-prefixed bindings whose initializers are constant expressions - Arithmetic, comparison, logical, and string concatenation operations where all operands are constant
- Calls to const functions (
$-prefixed) where all arguments are constant
42 // constant
1 + 2 * 3 // constant
"hello" + " world" // constant
true && false // constant
$square(x: $a) // constant if $square is const and $a is constant
The following are not constant expressions:
- References to mutable bindings
- Calls to non-const functions
- Expressions using capabilities
- Expressions containing runtime values (function parameters, loop variables)
Arithmetic overflow in a constant expression is a compile-time error, not a runtime panic.
See Clause 24 for evaluation limits and detailed rules.
12.7 Imports
When importing immutable bindings, the $ shall be included:
// config.ori
pub let $timeout = 30s;
// client.ori
use "./config" { $timeout }; // OK
use "./config" { timeout }; // error: 'timeout' not found
12.8 Constraints
- Module-level bindings shall use
$prefix (immutable required) $-prefixed bindings cannot be reassigned$and non-$bindings with the same name cannot coexist in the same scope