This section describes Austral’s basic built in types.
The Unit Type
The Unit
type is the simplest type: it has a single value, the constant nil
.
let unit: Unit := nil;
This is the equivalent of C’s void
: functions which don’t return anything
useful can return nil
:
function foo(): Unit is
return nil;
end;
Booleans
The built in Bool
type has two values: the constants true
and false
. if
and while
statements require boolean arguments, there are no implicit type
conversions or “truthy” values in Austral.
let t: Bool := true;
let f: Bool := false;
if t then
printLn("true!");
else
printLn("false!");
end if;
The not
, and
, and or
operators do what you expect. If a
and b
are
expressions of type Bool
, you can write:
not a
a and b
a or b
a and (not b)
Just as with arithmetic, there is no operator precedence for logical operators in Austral: any expression beyond one level has to be fully parenthesized:
-- Not valid:
a and b and c and d
-- Valid:
a and (b and (c and d))
Integers
The following are Austral’s built-in integer types:
Name | Width | Signedness |
---|---|---|
Nat8 |
8 bits | Unsigned. |
Nat16 |
16 bits. | Unsigned. |
Nat32 |
32 bits. | Unsigned. |
Nat64 |
64 bits. | Unsigned. |
Int8 |
8 bits. | Signed. |
Int16 |
16 bits. | Signed. |
Int32 |
32 bits. | Signed. |
Int64 |
64 bits. | Signed. |
Index |
Platform-dependent. | Unsigned. |
Nat
types are unsigned, they are natural numbers: they start at
zero. Int
types are signed, they are integers: they can hold negative and
positive values. The number is the width or size of the integer in bits.
The Index
type is a special case: it’s the type of array indices, and
equivalent to C’s size_t
type.
The minimum and maximum values of each type are:
Name | Minimum | Maximum |
---|---|---|
Nat8 |
0 | 28-1 = 255 |
Nat16 |
0 | 216-1 = 65,535 |
Nat32 |
0 | 232-1 = 4,294,967,295 |
Nat64 |
0 | 264-1 = 18,446,744,073,709,551,615 |
Int8 |
-27 = -128 | 27-1 = 127 |
Int16 |
-215 = -32,768 | 215-1 = 32,767 |
Int32 |
-231 = -2,147,483,648 | 231-1 = 2,147,483,647 |
Int64 |
-263 = -9,223,372,036,854,775,808 | 263-1 = 9,223,372,036,854,775,807 |
Index |
0 | Platform-dependent. |
The usual arithmetic operators are defined. If a
and b
are variables of the same integer type, you can write:
-a
a + b
a - b
a * b
a / d
Two notes:
-
First, Austral has no arithmetic precedence: any arithmetic operation (or any binary operation, including Boolean and comparison operations) deeper than one level has to be fully parenthesized. The following will not parse:
a - f(b - c/d) / e
Instead:
a - (f(b - (c/d)) / e)
-
Second, Austral has no implicit type conversions. If you need to do arithmetic with types having different sizes and signedness, you have to convert them first.
Note on Overflow
Austral’s built-in arithmetic operators abort on overflow. If you want modular semantics, or you don’t want to pay the performance cost of overflow checking and can prove that overflow won’t happen, you can use the modular arithmetic methods:
modularAdd(a, b);
modularSubtract(a, b);
modularMultiply(a, b);
modularDivide(a, b);
Floating-Point Numbers
Austral has two built-in floating-point types: Float32
is equivalent to C’s
float
and Float64
is equivalent to C’s double
. The arithmetic operators
work on floats as well, but the usual restrictions apply: you can’t mix
different float types, or floats and integers, in the same expression, you have
to convert them.
Spans
String literals are spans of bytes:
let str: Span[Nat8, Static] := "Hello, world!";
The size of a span can be obtained with the built-in spanLength
function,
which takes a span and returns a value of type Index
:
let size: Index := spanLength("Hello, world!");
Span elements can be accessed through the index operator:
let str: Span[Nat8, Static] := "Hello, world!";
printLn(str[0]);
If an index is out-of-bounds, the program aborts.