← Back to AILP Home

Array — array

Overview

Standard contiguous arrays with compile-time sizing.

Declaration

int32[5]:numbers;
numbers[0] = 10i32;
numbers[1] = 20i32;
numbers[2] = 30i32;
numbers[3] = 40i32;
numbers[4] = 50i32;

Access

int32:first = numbers[0];     // zero-indexed
int32:last = numbers[4];
if (numbers[2] != 30i32) {
    // handle error
}

Slicing (v0.35.1)

Slice syntax uses a half-open range [lo, hi) — element lo is included, element hi is excluded:

int64[5]:nums = [10, 20, 30, 40, 50];
int64[]:view = nums[1..3];   // elements at index 1, 2 — [20, 30]
int64[]:head = nums[0..2];   // first two elements — [10, 20]
int64[]:tail = nums[3..5];   // last two elements — [40, 50]

Slice bounds are checked at runtime; an out-of-bounds slice (lo < 0, hi > len, or hi < lo) routes through the failsafe with error code 45. A slice is a view into the original array's storage — reads and writes alias the source; no copy is made.

Multi-Dimensional Arrays (v0.19.0)

Nitpick supports 2-D (and higher) arrays with nested bracket syntax:

int32[2][2]:sq = [[1, 2], [3, 4]];
int32:top_right = sq[0][1];    // 2

int32[3][4]:tbl;
int32:r = 1;
int32:c = 3;
tbl[r][c] = 42;
int32:val = tbl[r][c];         // 42

The first bracket is the outer (row) dimension; the second is the inner (column) dimension. Access uses arr[row][col] for 2-D arrays.

Deprecated (v0.35.2): The legacy comma form arr[i, j] still parses but emits ARIA-MULTIDIM-COMMA-DEPRECATED. Use arr[i][j] instead. Hard rejection is planned for ≥ v0.40.x.

Array Iteration (v0.35.3)

for elem in arr { ... } iterates every element of a fixed-size array or a dynamic slice view:

int32[4]:nums = [10, 20, 30, 40];
for n in nums {
    // n is int32, visited in order: 10, 20, 30, 40
};

// Parenthesized form is also accepted:
for (n in nums) {
    // same
};

Explicit type annotation on the iterator is checked against the element type:

int64[3]:big = [100, 200, 300];
for int64:v in big {
    // v is int64 — annotation matches element type
};
// for int32:v in big { ... }  — COMPILE ERROR: int32 ≠ int64

Slice views are also iterable:

int32[5]:arr = [1, 2, 3, 4, 5];
int32[]:view = arr[1..4];   // [2, 3, 4]
for x in view {
    // x visits 2, 3, 4
};

## Dynamic-Index Borrows (v0.19.0)

Array elements can be borrowed with `$$i` (immutable) or `$$m` (mutable) using
a variable as the index. The borrow checker treats any variable-index borrow as
targeting the entire array (path `[*]`) since the slot is not known at
compile time:

```nitpick
int32[3]:arr = [10, 20, 30];
int32:i = 1;

$$i int32:elem = arr[i];   // immutable borrow — read only
// arr is locked for mutation while elem is live

$$m int32:slot = arr[i];   // mutable borrow — write-back on release
slot = 99;
// arr[1] is now 99 after slot goes out of scope

Conflict rules:

// COMPILE ERROR — both borrow the same array's [*] path
$$m int32:a = arr[i];
$$m int32:b = arr[j];   // ARIA-023

// COMPILE ERROR — literal arr[0] conflicts with dynamic arr[i]
$$m int32:lit = arr[0];
$$m int32:dyn = arr[i]; // ARIA-023

Arrays-in-Structs Borrow Interaction (v0.19.0)

When a struct contains an array field, split borrows work across disjoint paths — a scalar field and an array element are distinct paths:

struct:Pair = {
    int32:a;
    int32[4]:buf;
};

Pair:p;
p.a = 10;
p.buf[1] = 2;

$$m int32:ra = p.a;       // borrows path p.a
$$m int32:rb = p.buf[1];  // borrows path p.buf[1] — disjoint from p.a
ra = 3;
rb = 5;
// p.a == 3, p.buf[1] == 5 after both borrows release

Related