Skip to content

Array types

An array is a contiguous, fixed-size block of elements of the same type. The size is part of the type and cannot change after declaration.

Syntax

The array type is written as the element type followed by square brackets:

int[32]    // array of 32 integers
char[256]  // array of 256 chars
int[]      // incomplete array (see below)

Layout

An array is a contiguous block of memory. The array value points to the first element; subsequent elements follow at byte offsets scaled by the element size.

//  [element0][element1][element2]
//   ^
// array

For int (8 bytes), int[3] is laid out as:

Index Offset (bytes)
0 0
1 8
2 16

Byte-scaled pointer arithmetic

Gofra pointer arithmetic is byte-scaled, not element-scaled. To reach element i of int[N], add i 8 * (i sizeof int *) bytes — not i. The [] operator does this scaling automatically.

Initialization

Initialization depends on storage duration:

Storage Initialization
Global / static Zero-initialized
Stack (local) Uninitialized — reading before writing is UB

"Uninitialized stack arrays"

Stack arrays are not zero-initialized. The contents are whatever was on the stack before. Always initialize before reading.

List initializer

An array can be initialized with a list of values:

var a int[3] = [1, 2, 3]

The array size must match the number of values:

var a int[3] = [1, 2, 3]    // OK
var b int[2] = [1, 2, 3]    // error: too many values
var c int[4] = [1, 2, 3]    // error: too few values

Filler

To fill the remaining elements with a value, use ; followed by the filler:

var a int[5] = [1, 2, 3; 0]    // [1, 2, 3, 0, 0]

The filler applies to all elements after the explicitly listed ones.

Manual initialization

For other types, or to set values conditionally, write to elements directly:

var a int[3]
&a[0] 10 !<
&a[1] 20 !<
&a[2] 30 !<

After this, all three elements are initialized and safe to read.

Accessing elements

The [] operator computes the address of the element at the given index:

var a int[32]

a[0]    // int — first element
a[3]    // int — fourth element

The index can be a constant or a variable:

var i int = 3
a[i]    // int — element at index `i`

Pointer arithmetic equivalent

a[i] is equivalent to:

a 8 i * +    // a + (8 * i) — for int (8 bytes)

Bounds checking

Gofra performs compile-time bounds checking where the index is a constant:

var a int[5]
a[5]    // compile error: index out of bounds for `int[5]`

Runtime bounds are not checked

When the index is a runtime value, Gofra does not check bounds. Accessing out-of-bounds memory is undefined behavior (segfault).

This can be overriden via experimental flag: --rt-bounds-checks/--oob-checks

Incomplete arrays

An incomplete array type is written T[] — with no size. It cannot be used as a variable or field type:

var x int[]    // error: incomplete array type

It is used as a function parameter type, meaning "an array of any size":

func void process[*int[]]
    // ...
end

The function accepts *int[N] for any N:

var a int[32]
var b int[1]

&a call process    // OK
&b call process    // OK

No size information

An incomplete array parameter does not carry its length. If the function needs the size, pass it as a separate parameter.