Types
Andy C++ runs as a dynamically typed language — values carry their types at runtime and most checking happens then. You can also attach type annotations to variables, function parameters, and return values, and the analyser will use them to flag obvious mismatches before the program runs.
The type system is hierarchical with Any at the root:
AnyOption<T>BoolInt— checked signed 64-bit integersFloat— IEEE 754f64valuesNumber— arbitrary-size, rational, floating-point, and complex valuesSequence<T>String: a mutable list of charactersList<T>: a mutable listTuple<T, ...>: an immutable list(): unit, the empty tuple
Map<K, V>: a hashmap that associates keys with valuesDeque<T>: a double-ended queueMinHeap<T>/MaxHeap<T>: min/max heapIterator<T>: produces values when consumed (currently only from range expressions like5..100)
Function- Structs: user-defined record types, one per
structdeclaration
These are also the names you write in annotations. Generic types take their parameters in angle brackets:
let xs: List<Int> = [1, 2, 3];
let table: Map<String, Int> = %{"a": 1, "b": 2};
let maybe: Option<Any> = Some("hi");
let pair: Tuple<Int, String> = (1, "hi");
let pair2: (Int, String) = (1, "hi"); // tuple shorthand
Nested generics work too — the parser handles the >> ambiguity for you:
let grid: List<List<Int>> = [[1, 2], [3, 4]];
Struct names are type names like any other, including inside generics:
struct Point { x: Int, y: Int }
fn manhattan(p: Point) => p.x + p.y
let points: List<Point> = [Point(1, 2), Point(3, 4)];
A struct name refers to the struct declared earlier in an enclosing scope; it cannot be used before (or inside) its own declaration, and it goes out of scope together with the block or function that declared it. See Struct for the scoping rules.
Note:
Anyis the base type for every other type, so anAny-annotated binding will accept anything. When a parameter or value has no annotation and the analyser can’t infer a type, it falls back toAny. There is also aNevertype used internally for things likebreakthat don’t produce a value — you’ll rarely need to write it by hand.
To go the other way — recover a precise type from an Any-typed value — use a cast: value as List<Int>.