Types

Primitives

Type

Description

Size (Bits)

i8

8-bit signed integer

8

i16

16-bit signed integer

16

i32

32-bit signed integer

32

i64

64-bit signed integer

64

u8

8-bit unsigned integer

8

u16

16-bit unsigned integer

16

u32

32-bit unsigned integer

32

u64

64-bit unsigned integer

64

f32

32-bit floating point number

32

f64

64-bit floating point number

64

bool

boolean (true or false)

8

usize

pointer-sized unsigned integer

pointer size

addr

opaque pointer

pointer size

Pointers

Pointers store references to other values. They can be dereferenced to access the value they point to.

var a: i32 = 100;

# Creating a pointer to a variable
var ptr: *i32 = &a;

# Dereferencing the pointer
println(*ptr);  # 100

# Modifying the pointee
*ptr = 50;
println(a);  # 50

# Creating a null pointer
var null_ptr: *i32 = null;

Structs

Structs are types that group multiple values together. A value that is stored in a struct is called a field:

use std.math.sqrt;

struct Vec2 {
    pub var x: f32;
    pub var y: f32;

    pub func new(x: f32, y: f32) -> Vec2 {
        return Vec2 {
            x: x,
            y: y,
        };
    }

    pub func length(self) -> f32 {
        return sqrt(self.x * self.x + self.y * self.y);
    }
}

Enums

Enums store one of a set of possible values:

enum Fruit {
    APPLE,
    BANANA,
    ORANGE,
}

func main() {
    var fruit = Fruit.BANANA;
    println(fruit);
    println(fruit as u32);
}

In most situations, the enum type can be inferred from context:

enum Format { BINARY, JSON, XML }

func main() {
    var extension = extension_of(.JSON);
}

func extension_of(format: Format) -> StringSlice {
    if format == .BINARY {
        return ".bin";
    } else if format == .JSON {
        return ".json";
    } else if format == .XML {
        return ".xml";
    } else {
        return "";
    }
}

Unions

Union values contain one of multiple possible cases. The different cases can each contain their own fields, similar to structs:

union Shape {
    case Circle(radius: u32);
    case Rectangle(width: u32, height: u32);
}

func main() {
    # Union cases can be coerced to unions
    var shape: Shape = Shape.Rectangle(100, 50);
    print_shape(&shape);
}

func print_shape(shape: *Shape) {
    # Switch statements are used to both check and access the active case
    switch *shape {
        case circle: Shape.Circle {
            println("circle");
            print("  radius: ");
            println(circle.radius);
        } case rectangle: Shape.Rectangle {
            println("rectangle");
            print("  width: " );
            println(rectangle.width);
            print("  height: " );
            println(rectangle.height);
        }
    }
}

Tuples

Tuples group related data together, similar to structs. The fields don’t have a name and are referenced by their index in the tuple.

var a: (i32, bool) = (100, true);
println(a.0);  # 100
println(a.1);  # true

a.1 = false;
println(a.1);  # false

Tuples are useful for returning multiple values from functions:

func get_coordinates() -> (i32, i32) {
    return (-10, 25);
}

Arrays

Arrays store a list of values with the same type:

# Initializing arrays with a literal
var array: [i32] = [1, 2, 3];

# Accessing array elements
println(array[0]);
array[0] = 20;

# Iterating over the elements
for ref value in array {
    println(value);
}

# Arrays are dynamic
array.append(4);

# Arrays can be iterated over by reference to modify values
for ref mut value in array {
    value = 100;
}

Optionals

Optionals store either a value or none:

func main() {
    # Initializing an optional with a value
    var opt1: ?i32 = 100;
    println(opt1.has_value);  # true
    println(opt1.value);  # 100

    # Initializing an empty optional
    var opt2: ?u64 = none;
    println(opt2.has_value);  # false
}

Slices

Slices store a pointer to some data and its length. There are multiple ways of creating a slice:

func main() {
    # Initializing a slice directly from a pointer and a length
    var value: (i32, i32) = (2, -1);
    var slice_1 = Slice[i32].new(&value.0, 2);

    # Creating a slice from a dynamic array
    var array = [0, 1, 2];
    var slice_2 = array.slice();

    # Creating a slice from an array literal
    var slice_3: Slice[i32] = [0, 1, 2];
}

Slices are used in a similar way to arrays. You can access their elements and iterate over them:

func main() {
    var slice: Slice[f32] = [1.2, 0.5, -3.8];

    # Getting an element from the slice
    println(slice[1]);  # 0.5

    # Getting the length of a slice
    println(slice.length());  # 3

    # Iterating over the elements in the slice
    for ref value in slice {
        println(value);
    }

    # Getting a subslice (using a start and end index)
    var subslice = slice.subslice(1, 3);
    println(subslice[0]);  # 0.5
    println(subslice[1]);  # -3.8

    # Getting the bytes in the slice
    var bytes: Slice[u8] = slice.as_bytes();
}

Importantly, slices don’t own the data, they just point to it. This means a slice becomes invalid after the backing data is deallocated:

func bad_slice() -> Slice[bool] {
    var slice: Slice[bool] = [false, true];
    return slice;  # BROKEN: Returning a slice to stack-allocated data
}

String Slices

String slices are similar to normal slices, but they reference string data instead of a generic sequence of values. Creating them is analogous to normal slices:

func main() {
    # Initializing a string slice directly from a pointer and a length
    var value: *u8 = "c string";
    var string_slice_1 = StringSlice.new(&value[0], 4);

    # Creating a string slice from a string
    var string = "owned string";
    var string_slice_2 = string.slice();

    # Creating a string slice from a string literal
    var string_slice_3: StringSlice = "literal";
}

String slices are used like strings:

func main() {
    var str: StringSlice = "some text";

    # Printing the string slice
    println(str);  "some text"

    # Getting the length of the string slice
    println(str.length());  # 9

    # Checking the value of the string slice
    println(str == "some text");  # true

    # Getting a substring (using a start and end index)
    var substring = str.substring(5, 9);
    println(substring);  # "text"
}