An array [T] is a growable list of values of one type. Arrays are values:
let b = a gives you an independent copy (made lazily, so it’s cheap), and an
index outside the array stops the program unless the compiler proved it can’t
happen.
fn main(): var xs = [3, 1, 2] xs.push(5) xs.sort() print(xs, len(xs), xs[0], 5 in xs)[1, 2, 3, 5] 4 1 trueMaking arrays
Section titled “Making arrays”Write the elements in brackets, repeat one value with * n, or build an array
with a comprehension:
fn main(): let primes = [2, 3, 5, 7] let zeros = [0.0] * 4 let squares = [i * i for i in 0..6] let even_squares = [i * i for i in 0..10 if i % 2 == 0] let words = ["fig", "pear", "plum"] let lengths = [len(w) for w in words] print(primes, zeros, squares) print(even_squares, lengths)[2, 3, 5, 7] [0.0, 0.0, 0.0, 0.0] [0, 1, 4, 9, 16, 25][0, 4, 16, 36, 64] [3, 4, 4][x] * nmakesncopies ofx. The value goes on the left:3 * [0]is an error. A negativenpanics.- A comprehension is
[expr for name in iterable]with an optionalif filter. The iterable is a range (0..n,0..=n,range(a, b, step)), an array, a string or a map. Tuples unpack:[name for name, age in people if age > 30]. - One
forper comprehension:[x for row in grid for x in row]is an error (E0110). Use a loop withextendinstead. - An empty array needs a type:
var names: [str] = [].let xs = []alone is error E0308.
par [...] builds the array on every core. See
parallelism.
Reading elements
Section titled “Reading elements”fn main(): let xs = [10, 20, 30, 40] print(xs[0], xs[len(xs) - 1], len(xs)) print(20 in xs, xs.contains(99), 99 not in xs) print(xs.index(30), xs.index(99)) print(xs == [10, 20, 30, 40], xs != [40, 30, 20, 10])10 40 4true false trueSome(2) Nonetrue truexs[i]reads elementi, counting from 0.x in xsandxs.contains(x)are the same test.xs.index(x)returnsOption[int]:Some(i)for the first match,Noneif there is none. See error handling forOption.==and!=compare length and every element. Arrays have no<: only numbers and strings are ordered.
An index outside the array is a panic:
fn main(): let xs = [1, 2, 3] let i = len(args()) + 5 print(xs[i])panic: index 5 is out of bounds for an array of length 3 --> main.br:4:11The program exits with code 101. When the compiler can prove an index is in range
(as in for i in 0..len(xs): xs[i]), it removes the check. brine check --report
lists the checks that remain. See proofs.
No negative indexes
Section titled “No negative indexes”Brine has no negative indexes. xs[-1] isn’t the last element; it’s out of
bounds, and panics like any other bad index. Write the index out:
fn main(): let xs = [1, 2, 3] let last = xs[len(xs) - 1] let tail = xs[len(xs) - 2:] print(last, tail)3 [2, 3]Python’s xs[-1] hides an off-by-one when the index is computed: i - 1 with i
at 0 silently gives the last element. In Brine it stops with a clear message.
Changing an array
Section titled “Changing an array”Methods that change an array need a var:
fn main(): var xs = [3, 1, 2] xs.push(5) let last = xs.pop() let first = xs.pop(0) print(last, first, xs) xs.insert(0, 9) xs.extend([7, 8]) print(xs) xs.sort() print(xs) xs.reverse() print(xs) xs[0] = 100 xs[1] += 1 print(xs) xs.clear() print(xs, len(xs))5 3 [1, 2][9, 1, 2, 7, 8][1, 2, 7, 8, 9][9, 8, 7, 2, 1][100, 9, 7, 2, 1][] 0pop()on an empty array panics (pop() from an empty array), and so dopop(i)andinsert(i, x)withiout of range.insert(len(xs), x)appends.sort()works on arrays of numbers and strings and is stable. Arrays of tuples, structs orboolcan’t be sorted (E0305).- There is no
+for arrays. Useextend.
Slices
Section titled “Slices”xs[a:b] is a new array with the elements from index a up to, not including,
b. Leave out a to start at 0 and b to go to the end:
fn main(): let xs = [10, 20, 30, 40, 50] var middle = xs[1:4] middle[0] = 0 print(middle, xs[:2], xs[3:], xs[5:], xs[:]) print(xs)[0, 30, 40] [10, 20] [40, 50] [] [10, 20, 30, 40, 50][10, 20, 30, 40, 50]A slice is a copy: changing it never changes the original. Bounds must satisfy
0 <= a <= b <= len(xs); anything else panics, with no clamping as in Python:
panic: slice [1:5] is out of bounds for an array of length 3Nested arrays
Section titled “Nested arrays”An array can hold arrays. Build a grid with a comprehension, so each row is its own value:
fn main(): var grid = [[0] * 3 for _ in 0..2] grid[1][2] = 7 let copy = grid grid[0][0] = 1 print(grid) print(copy) print(len(grid), len(grid[0]), grid[1][2])[[1, 0, 0], [0, 0, 7]][[0, 0, 0], [0, 0, 7]]2 3 7[[0] * 3] * 2 works too. Because arrays are values, its rows are independent:
setting g[0][0] changes only the first row, unlike Python lists.
Arrays are values
Section titled “Arrays are values”Assigning an array, passing it to a function, or storing it in a struct copies it. The copy is lazy (copy-on-write): both names share one buffer until one of them changes, and only then is the buffer copied. Copies cost almost nothing, and changing one array never changes another.
fn add_one(mut xs: [int]) -> [int]: for i in 0..len(xs): xs[i] += 1 return xs
fn main(): var a = [3, 1, 2] let b = a a.sort() let c = add_one(a) print(a, b, c)[1, 2, 3] [3, 1, 2] [2, 3, 4]To let a function change the caller’s array, pass it by reference:
fn fill(ref xs: [int], v: int), called as fill(ref data, 0). See
functions.
Looping over an array
Section titled “Looping over an array”for x in xs walks a snapshot of xs taken when the loop starts, so the body may
change xs safely:
fn main(): var xs = [1, 2, 3] for x in xs: xs.push(x * 10) print(xs) for i, x in enumerate(["a", "b"]): print(i, x)[1, 2, 3, 10, 20, 30]0 a1 bThe loop runs three times. Changes made in the body show up after the loop. See control flow for more loop forms.
One change per statement
Section titled “One change per statement”A statement can’t both change a variable and read it somewhere else, or change it twice. Otherwise the result would depend on which part runs first:
fn main(): var xs = [1, 2, 3] print(xs.pop(), xs)error[E0405]: `xs` is changed and also read in the same expression --> main.br:3:11 |3 | print(xs.pop(), xs) | ^^^^^^^^ changed here | -- read here | = help: make the change in its own statement first, then use the result = run `brine explain E0405` for more about this errorerror: could not compile due to 1 errorSplit it in two: let last = xs.pop(), then print(last, xs). The same applies
to xs.push(xs.pop()). Reading the array in the changing call’s own arguments
is fine (xs.push(len(xs))), and so is using it on the two sides of and, or
or if ... else. See E0405.
Reductions
Section titled “Reductions”sum, product, min, max, any and all take a generator: a comprehension
without the brackets. No array is built.
fn main(): let xs = [4, -2, 8, 5] print(sum(x for x in xs), product(x for x in xs)) print(min(x for x in xs), max(x * x for x in xs)) print(any(x < 0 for x in xs), all(x < 10 for x in xs)) print(sum(i for i in 0..101 if i % 2 == 0)) print(sum(float(x) / 2.0 for x in xs))15 -320-2 64true true25507.5- Over an empty sequence,
sumis 0,productis 1,anyisfalseandallistrue.minandmaxpanic:min() of an empty sequence. min(a, b)andmax(a, b)with two arguments are the plain built-ins.- A generator can only be passed to one of these six;
len(x for x in xs)is error E0316. Use[x for x in xs]to build an array. - Overflow in a reduction panics like any other overflow.
par sum(...)and the others run on every core and give the same bits on any machine. See deterministic reductions.
Reference
Section titled “Reference”| Operation | Result | Notes |
|---|---|---|
len(xs) |
int |
|
xs[i] |
T |
panics if out of range; no negative indexes |
xs[a:b], xs[:b], xs[a:] |
[T] |
a copy; panics if out of range |
x in xs, xs.contains(x) |
bool |
|
xs.index(x) |
Option[int] |
first match |
xs == ys |
bool |
element by element |
xs.push(x) |
append | |
xs.pop() |
T |
remove the last; panics if empty |
xs.pop(i) |
T |
remove at i, shifting the rest left |
xs.insert(i, x) |
put x at i, shifting the rest right; 0 <= i <= len(xs) |
|
xs.extend(ys) |
append every element of ys |
|
xs.sort() |
numbers and strings; stable | |
xs.reverse() |
||
xs.clear() |
remove everything | |
sum, product, min, max, any, all |
over a generator: sum(x for x in xs) |
- Elements all have one type. An empty array needs an annotation.
- Indexes start at 0 and are never negative. Out-of-range indexes and slices panic.
let b = acopies; changingbnever changesa.for x in xsloops over a snapshot.- A statement can’t change an array and read it elsewhere.
Related: strings, maps, values and types, built-in functions.