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 builtin 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 
Platformdependent.  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  2^{8}1 = 255 
Nat16 
0  2^{16}1 = 65,535 
Nat32 
0  2^{32}1 = 4,294,967,295 
Nat64 
0  2^{64}1 = 18,446,744,073,709,551,615 
Int8 
2^{7} = 128  2^{7}1 = 127 
Int16 
2^{15} = 32,768  2^{15}1 = 32,767 
Int32 
2^{31} = 2,147,483,648  2^{31}1 = 2,147,483,647 
Int64 
2^{63} = 9,223,372,036,854,775,808  2^{63}1 = 9,223,372,036,854,775,807 
Index 
0  Platformdependent. 
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 builtin 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);
FloatingPoint Numbers
Austral has two builtin floatingpoint 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.
Fixed Arrays
Fixed arrays are the type of (usually statically allocated) arrays. String literals are fixed arrays of bytes:
let str: FixedArray[Nat8] := "Hello, world!";
The size of a fixed array can be obtained with the builtin fixedArraySize
function, which takes a fixed array and returns a value of type Index
:
let size: Index := fixedArraySize("Hello, world!");
Array elements can be accessed through the index operator:
let str: FixedArray[Nat8] := "Hello, world!";
printLn(str[0]);
If an array index is outofbounds, the program aborts.