16  Vectors

The builtin vector type provides a simple but powerful abstraction for creating collections of objects of the same type. In terms of functionality, a vector is close to plain arrays as defined in most programming languages. Vectors implement the iterable protocol so they can be iterated with a for syntax.

Vectors in HULK can be defined with two different syntactic forms: explicit and implicit.

16.1 Explicit syntax

An explicit vector of Number, for example, can be defined as follows:

let numbers = [1,2,3,4,5,6,7,8,9] in
    for (x in numbers)
        print(x);

Because vectors implement the iterable protocol, you can explicitely find a next and current methods in case you ever need them. Besides that, vectors also have a size(): Number method that returns the number of items in the vector.

Vectors also support an indexing syntax using square brackets [], as in the following example:

let numbers = [1,2,3,4,5,6,7,8,9] in print(numbers[7]);

16.2 Implicit syntax

An implicit vector can be created using what we call a generator pattern, which is always an expression.

Here’s one example:

let squares = [x^2 | x in range(1,10)] in print(x);
// prints 2, 4, 6, 8, 10, ...

In general, the syntax has the form [<expr> | <symbol> in <iterable>], where <expr> is run in a new scope where symbol is iteratively bound to each element in the vector.

16.3 Typing vectors

Since vectors are iterables, you can safely pass a vector as argument to method that expects an iterable:

function sum(numbers: Number*): Number =>
    let total = 0 in
        for (x in numbers)
            total := total + x;

let numbers = [1,2,3,4,5] in
    print(sum(numbers));

However, inside sum you cannot use the indexing operator [] or the size method, because the argument is typed as an iterable, and not explicitly as a vector. To fix this, HULK provides another special syntax for vectors, using the T[] notation:

function mean(numbers: Number[]): Number =>
    let total = 0 in {
        for (x in numbers)
            total := total + x;

        // here `numbers` is known to be vector
        total / numbers.size();
    };

let numbers = [1,2,3,4,5] in
    print(mean(numbers));

Like with iterables, what happens under the hood is that the compiler implicitely defines a type with the following structure:

type Vector_T {
    size() {
        // impementation of size ...
    }

    iter(): Iterable_T {
        // implementation of iter
    }
}