Builtin types

Type Meaning
int alias of int32, default type for integer literals
int8 8-bit signed integer
sbyte alias of int8
int16 16-bit signed integer
int32 32-bit signed integer
int64 64-bit signed integer
uint alias of uint32
uint8 8-bit unsigned integer
byte alias of uint8
uint16 16-bit unsigned integer
uint32 32-bit unsigned integer
uint64 64-bit unsigned integer
c_size_t C size_t type (pointer-sized unsigned integer: 32-bit on wasm32, 64-bit on 64-bit targets)
c_schar C signed char type (8-bit signed integer)
c_uchar C unsigned char type (8-bit unsigned integer)
c_short C short type (16-bit signed integer)
c_ushort C unsigned short type (16-bit unsigned integer)
c_int C int type (32-bit signed integer)
c_uint C unsigned int type (32-bit unsigned integer)
c_long C long type (32-bit signed integer on Windows and wasm32, 64-bit on 64-bit Unix targets)
c_ulong C unsigned long type (32-bit unsigned integer on Windows and wasm32, 64-bit on 64-bit Unix targets)
c_longlong C long long type (64-bit signed integer)
c_ulonglong C unsigned long long type (64-bit unsigned integer)
c_float C float type (32-bit floating-point number)
c_double C double type (64-bit floating-point number)
float alias of float32, default type for floating-point literals
float32 32-bit floating-point number
float64 64-bit floating-point number
double alias of float64
bool boolean
char C/C++ char type

Numeric literals

Integer literals are decimal by default. Underscores may separate digits for readability (1_000_000), and the prefixes 0x, 0o, and 0b select hexadecimal, octal, and binary.

Floating-point literals have a fraction (.5 is written 0.5), a base-10 exponent introduced by e or E with an optional sign, or both:

void main() {
    println(1_000_000); // prints 1000000
    println(0xFF); // prints 255
    println(0o17); // prints 15
    println(0b101); // prints 5
    println(100.0); // prints 100
    println(1e10); // prints 1e+10
    println(1.5e-3); // prints 0.0015
    println(2E+2); // prints 200
}

Arithmetic operators

There are the usual arithmetic operators +, -, *, /, %, %%, &&, ||, !, &, |, ^, ~, <<, >>, wrapping operators +%, -%, *%, saturating operators +|, -|, *|, <<|, and the compound assignment counterparts for the binary operators: +=, -=, *=, /=, %=, &&=, ||=, &=, |=, ^=, <<=, >>=, +%=, -%=, *%=, +|=, -|=, *|=, <<|=.

An important thing to note about +, -, and * is that they don't silently wrap on overflow. Instead they abort with an "integer overflow" error, except in release mode (--release), where overflow is unchecked and wraps. Overflow checks can also be disabled for a single function, statement, or expression with @noOverflowCheck (or @unchecked for all safety checks). Unary - is checked the same way: negating the minimum value of a signed type, or any nonzero unsigned value, aborts. Constant arithmetic is checked at compile time: a constant +, -, *, or unary - whose result doesn't fit its type is an error in every build mode.

Wrapping operators +%, -%, and *% (and +%=, -%=, *%=) wrap on overflow with two's-complement wraparound. Unary -% is wrapping negation. Saturating operators +|, -|, *|, and <<| (and +|=, -|=, *|=, <<|=) clamp to the type's minimum or maximum instead. These operators work on integers only, in every build mode, including on constant expressions:

void main() {
    println(byte(255) +% 1); // prints 0
    println(byte(255) +| 1); // prints 255
    println(byte(200) *% 2); // prints 144
    println(byte(200) *| 2); // prints 255
    int8 min = -128;
    println(-%min); // prints -128
    println(byte(1) <<| 8); // prints 255
}

The % operator is a truncated remainder: its result takes the sign of the dividend, so -7 % 3 is -1. The %% operator is a positive remainder instead: its result takes the sign of the divisor, so with a positive divisor the result is always in the range 0 to divisor - 1.

void main() {
    println(7 % 3); // prints 1
    println(-7 % 3); // prints -1
    println(7 %% 3); // prints 1
    println(-7 %% 3); // prints 2
}

Increment and decrement operators

The increment and decrement operators, written as postfix ++ and --, respectively, increment/decrement their operand by one. They can only be used as standalone statements, not inside arbitrary expressions.

sizeof

sizeof(T) and sizeof(x) are constant integer expressions. When the type has to be inferred, as in var s = sizeof(T), it is int. In an arithmetic expression the sizeof operand takes the other operand's numeric type, so sizeof(Element) * size has the type of size.

void main() {
    int n = 3;
    int64 wide = 3;
    var bytes = sizeof(int); // int
    var scaled = sizeof(int) * n; // int
    var scaledWide = sizeof(int) * wide; // int64
    println(bytes); // prints 4
    println(scaled); // prints 12
    println(scaledWide); // prints 12
}

Planned features