literals
The forms that write a value out directly: the primitive literals, and the composite forms for a struct, a tuple, and an array.
const tracking_enabled: bit = true;
const home_station: string = "GroundStation-1";
const max_tracks: uint16 = 512;
const earth_radius_m: float64 = 6378137.0;Primitive literals
One form per primitive type. A numeric literal carries no width of its own — see numeric type inference for what pins it.
trueandfalseare thebitliterals.- A string literal is
"-delimited, terminates on the line it opens, and recognizes the escapes\",\\,\n,\r, and\t. - An integer literal is decimal,
0xhexadecimal, or0bbinary, both prefixes lowercase. - A decimal literal needs an integer part, a
., and a fractional part, so0.5parses and.5does not. _separates decimal digits. A literal may not open or close with one, hold two in a row, or place one before the exponent marker.- An
e/Eexponent is a positive integer. The hexadecimal and binary forms accept neither_nor an exponent.
const label: string = "she said \"track\"";
const count: uint32 = 1_000_000;
const mask: uint8 = 0b10100000;
const signature: uint32 = 0x99aaBB;
const scale: float64 = 8.02838E16;Ascription
expr : Type pins an expression's type. It constrains inference and performs no conversion.
- The ascribed type becomes the expression's type, and an inner type it does not accept is a mismatch.
- Ascription binds below every operator, so an un-grouped ascription reaches as far left as it can:
1 + 2: int32ascribes the sum. - Parentheses are what ascribe one operand:
(1: int32) + 2.
(42: int16) // => 42
(1 + 2: int32) // => 3
(0.5: float32) // => 0.5Numeric type inference
A numeric literal stands for a width still to be decided, and unification with the constraints around
it decides one. Other forms open the same hole: an empty [] and a context-less none.
- Constraints come from an ascription, a typed binding, and a declared type — a
const's annotation, a return type, a parameter type, a struct field type — as well as from the operators applied. - Enforcement recurses through structure, so a declared
int32[]return type pins the literals in a comprehension over[1, 2, 3]. - Inference is solved one declaration at a time. No constraint crosses a declaration boundary, so a use of a declaration reads its declared type and never its initializer's holes.
- A width still unconstrained once its declaration is solved is reported. No width is guessed.
function scaled(factor: int32) -> int32[] = map(x in [1, 2, 3]) { x * factor; };Struct literals
TypeRef { field = expr; … } — one binding per field, each closed by a semicolon. The literal's type
is the referenced declaration.
- Every field gets exactly one binding, fields inherited through
extendsincluded. - Bindings may appear in any order, and each must be assignable to the field's declared type.
- A zero-field struct is written
Empty{}. TypeRef { base with field = expr; }copiesbaseand overrides the fields it names, so an update binds only what it changes.
struct TrackReport {
track_id: uint32;
bearing_deg: float32;
}
const initial: TrackReport = TrackReport { track_id = 1; bearing_deg = 87.5; };
const turned: TrackReport = TrackReport { initial with bearing_deg = 91.0; };Tuple literals
A parenthesized list of two or more expressions, typed by its elements in order.
- A single parenthesized expression is a grouping, not a one-element tuple.
- Each element's type is determined independently.
- An element may carry its own ascription, or the whole tuple may be ascribed.
const fix: (float64, float64) = (42.3601, -71.0589);
(1: int32, 2: int32) // => (1, 2)
((1, 2): (int32, int32)) // => (1, 2)
fix._1 // => -71.0589Array literals
A bracketed list of expressions of one type. A for after the first element makes it a comprehension
instead of a list.
- All elements share one type.
- An empty
[]takes its element type from context. ++concatenates two arrays of one element type.
const bearings: float32[] = [87.5, 91.0];
bearings ++ [(274.25: float32)] // => [87.5, 91, 274.25]
length(bearings) // => 2Errors
A numeric literal nothing pins
The width has to come from somewhere. An unconstrained literal is reported rather than defaulted.
function total(count: uint32) -> uint32 = {
let scaled = 2 * 8; // error: ambiguous-inferred-type
count;
};A field the struct does not declare
struct TrackReport {
track_id: uint32;
}
const initial: TrackReport = TrackReport { track_id = 1; bearing_deg = 87.5; }; // error: invalid-member-accessA field bound twice
struct TrackReport {
track_id: uint32;
bearing_deg: float32;
}
const initial: TrackReport = TrackReport { track_id = 1; track_id = 2; bearing_deg = 87.5; }; // error: duplicate-field-bindingA field left unbound
A literal states the whole value, so every field needs a binding. An update is the form that changes part of one.
struct TrackReport {
track_id: uint32;
bearing_deg: float32;
}
const initial: TrackReport = TrackReport { track_id = 1; }; // error: missing-field