Skip to content

Vectors

This section describes how to use fixed size and dynamic size vectors (arrays).

A vector is an ordered collection of one type of data that allows duplicates. In some languages these are called arrays or lists. You can think of it as a stack where something is on the bottom and new things are added or “pushed” to the collection. A vector can be fixed sized where it always has the same number of elements, or dynamically sized where elements can be added while the program runs.

Vectors are defined by using the “vec” keyword followed by the type of vector, and optionally, the quantity inside angle brackets: < >. A quantity is required for making a fixed size vector.

A fixed vector lives in memory on the “stack”, whereas a dynamic vector lives on the “heap”. Because of this, program code that uses fixed vectors will often run faster than if using dynamic vectors.

// Fixed vector signature: vec<type,quantity> variable_name
vec<i32,10> my_fixed_vec;
// Dynamic vector signature: vec<type> variable_name
vec<f32> my_dynamic_vec;
// Use the len() function to get the length of a vector.
println( len(my_fixed_vec) ); // 10
println( len(my_dynamic_vec) ); // 0

You can read and write to a slot in the vector by using square backets with the slot index after the variable name. Vector indexes start at [0]. This may seem strange at first, but it matches many other languages and works well with “for” loops and the modulus (%) operator.

// Put the number 5 in slot 0 of the vector "x":
x[0] = 5;
// Print the contents of slot 3 of the vector "x";
println(x[3]);

Warning: you can only read and write to valid indexes (inside the bounds of an array) or else the program will crash.

When a fixed size vector is created, all the memory is zero initialized (filled with zeros) unless specified using an initializer list [ ] expression.

// zero initializer
vec<i32,3> ivec;
println(ivec[0]); // 0
println(ivec[1]); // 0
println(ivec[2]); // 0
// initializer list
vec<i32,3> ivec = [ 1, 2, 3 ];
println(ivec[0]); // 1
println(ivec[1]); // 2
println(ivec[2]); // 3
// a variable can be used as the size as long as it is constant (unchangeable).
const i32 sz = 3;
vec<i32,sz> cvec; // make a new i32 vector with 3 zeros
println(cvec); // 0, 0, 0

Assignment examples:

// index assignment
println(ivec); // 1, 2, 3
ivec[1] = 4; // store 4 in slot 1 (the second slot)
println(ivec); // 1, 4, 3
// copy one vector to another.
vec<i32,3> avec; // make a new vector full of zeros
println(avec); // 0, 0, 0
avec = ivec; // copy ivec to avec
println(avec); // 1, 4, 3
// initialize by copying another vector
vec<i32,3> bvec = avec;
println(bvec); // 1, 4, 3
// variables can be used as indexes and in assignment
i32 idx = 1;
bvec[idx] = 6; // put 6 in slot 1
println(bvec); // 1, 6, 3
bvec[idx] = idx; // put 1 in slot 1
println(bvec); // 1, 1, 3
// assigning to index from variable with index
println(avec); // avec before: 1, 4, 3
println(bvec); // bvec before: 1, 1, 3
i32 i0 = 1;
i32 i1 = 2;
bvec[i1] = avec[i0]; // using variables as indexes
println(bvec); // bvec after: 1, 1, 4
bvec[1] = avec[2]; // using numbers as indexes
println(bvec); // bvec after: 1, 3, 4

When a dynamic size vector is created, it starts out completely empty unless specified using an initializer list { } expression.

// empty i32 vector
vec<i32> ivec;
println( len(ivec) ); // 0
// initializer list with redefinition
// -- the original "ivec" will get erased since we're reusing the variable name.
vec<i32> ivec = [ 1, 2, 3 ];
println(ivec); // 1, 2, 3
// brace { } expressions work during assignment as well.
vec<i32> ivec; // new empty vector
ivec = [ 1, 2, 3 ];
println(ivec); // 1, 2, 3
// index assignment works just like fixed size vectors
ivec[1] = 4;
println(ivec); // 1, 4, 3
// copy assignment works just like fixed size vectors
vec<i32> avec; // empty
avec = ivec;
println(avec); // 1, 4, 3
// initialization using copy just like fixed size vectors
vec<i32> bvec = avec;
println(bvec); // 1, 4, 3
// clearing a dynamic vector by assignment
vec<i32> avec = [ 1, 2, 3, 4 ];
avec = [];
println(avec); // "<DynVec,i32,Size:0>[]" <-- empty vector

Use the vec::push!() command to append a value to the end of a vector. The ! indicates that it is going to modify the vector you provide in the first parameter. The namespace vec:: is added to the command because this utility lives in the vec portion of the standard library.

Signature: vec::push!(vector_name, value_to_push);

// appending pushing values onto the end of a vector
vec<i32> avec = [ 1, 2, 3 ];
vec::push!(avec, 4);
println(avec); // "<DynVec,i32,Size:4>[1, 2, 3, 4]"

Sometimes you want to have code that loops through each item in a vector. This is performed by “iterating” and comes in a few flavors using the “for” loop.

The first method is to use a normal “for” loop with a counter that accesses each item in the vector.

// example fixed size vector of integers.
vec<i32,5> ints = [ 1, 2, 3, 4, 5 ];
// we're going to sum (add up) all values inside of ints starting from 0.
i32 sum; // 0 by default
// loop starting with i = 0, and exit once i = the length of ints (5).
for i in len(ints) {
sum = sum + ints[i]; // add to sum the item in ints at slot i.
}
println(sum); // 15
// same exact thing but without the for loop.
i32 sum;
sum = sum + ints[0];
sum = sum + ints[1];
sum = sum + ints[2];
sum = sum + ints[3];
sum = sum + ints[4];
println(sum); // 15

The second method gets a copy of each item in the vector instead of using a counter.

// example dynamic vector of floats
vec<f32> floats = [ 1.1, 2.2, 3.3, 4.4, 5.5 ];
f32 sum;
// loop over floats, and copy each value into "v".
for v in floats {
sum = sum + v; // add the value in v to sum
}
println(sum); // 16.5

The third method allows you to get a counter and the vector value during each loop.

// example vector of strings
vec<string> animals = [ "Cats", "Dogs", "Fish" ];
string output; // empty by default
for k,v in animals { // we want to use k for counter and v for value during each loop.
output += k as string + " " + v + "... ";
}
println(output); // "0 Cats... 1 Dogs... 2 Fish... "