Skip to main content

primitives

The built-in types every other type is composed from: bit, string, float32, float64, and the arbitrary-width integers intN and uintN.

const tracking_enabled: bit = true;
const home_station: string = "GroundStation-1";
const bearing_deg: float32 = 87.5;
const earth_radius_m: float64 = 6378137.0;
const max_tracks: uint16 = 512;
const altitude_m: int32 = -120;

bit​

The boolean primitive. It holds true or false, and it is not a numeric type.

  • bit is assignable only to bit. No integer converts to it, and no cast produces one.
  • &&, ||, ^, and ! are defined on it, as logical operators.
  • A match over a bit covers it by listing true and false.

string​

The character-sequence primitive. A literal is "-delimited and must be terminated on the line it opens.

  • The escapes are \", \\, \n, \r, and \t.
  • ++ concatenates two strings.
  • substring takes a half-open character range and fails when the range runs past the end.

Floats​

float32 and float64 are IEEE-754 single and double precision, and they are distinct types.

  • Neither is assignable to the other. value_cast<float64> widens; float64to32 narrows, and it is a built-in function rather than a cast because it loses precision.
  • Overflow yields inf and an invalid operation yields NaN, so float arithmetic never fails.
  • NaN is unordered, so every comparison is false against it and !(a < b) is not a >= b.

Integers​

intN is signed and uintN is unsigned, for any width N of one bit or more: int8, uint16, int37.

  • The width is written directly after the prefix, with no space and no leading zeros.
  • Two integer types are assignable only when identical. There is no widening and no signed/unsigned coercion, so a conversion is a value_cast.
  • Arithmetic is fixed-width and wraps on overflow, at the width the type declares.
  • Division truncates toward zero, and % takes the sign of its left operand.
  • Division by zero is a runtime failure, so try turns it into none.
const limit: uint8 = 250;
const ceiling: int8 = 127;

limit + 10         // => 4
ceiling + 1        // => -128
(-7: int32) / 2    // => -3
try(limit / 0)     // => none

Assignability​

A value is assignable to a target when the two types are the same type. These rules say what "the same" means, and nothing outside them converts on its own.

  • Primitives, enums, and named types match by name.
  • Arrays and optionals match on their inner types; tuples match position-wise and must have equal arity.
  • A numeric literal has no width of its own, so it is assignable to any type of its category: an integer literal to any intN or uintN, a decimal literal to either float.
  • A struct is assignable wherever one of its ancestors is expected.

Errors​

A value of another primitive type​

A value's type has to be the target's type exactly: there is no widening between integer widths, no conversion between the float types, and no coercion between bit and a number.

const short: int8 = 42;
const long: int16 = short;             // error: type-mismatch

const narrow: float32 = 0.5;
const wide: float64 = narrow;          // error: type-mismatch

const tracking_enabled: bit = 1;       // error: type-mismatch
  • value-cast — the conversions between numeric types.
  • operators — what each primitive supports.
  • literals — how a value of each type is written.