Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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:

  • Any
    • Option<T>
    • Bool
    • Number
      • Int — machine i64 or arbitrary-precision BigInt, picked automatically
      • Float
      • Complex
      • Rational
    • Sequence<T>
    • Function

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]];

Note: Any is the base type for every other type, so an Any-annotated binding will accept anything. When a parameter or value has no annotation and the analyser can’t infer a type, it falls back to Any. There is also a Never type used internally for things like break that don’t produce a value — you’ll rarely need to write it by hand.