Arrays, Ranges, and Iteration
Ferlium provides compact tools for working with sequences of values: arrays, ranges, and for loops. This chapter introduces how to create and read arrays, describe numeric sequences with ranges, and iterate over both forms in an expression-oriented style.
Arrays
Arrays store ordered values of a single element type.
Array literals
Array literals use square brackets:
let a = [1, 2, 3];
let b = [true, false, true];
let c = ["a", "b"];
A trailing comma is allowed:
let xs = [1, 2, 3,];
[] is valid syntax, but by itself its element type is unknown, so it needs context:
let empty: [int] = [];
Indexing
Use array[index] to access elements:
let xs = [10, 20, 30];
let first = xs[0];
let second = xs[1];
Use indexed assignment to update an element through a mutable array binding:
let mut xs = [10, 20, 30];
xs[1] = 25;
xs
Negative indices count from the end:
let xs = [10, 20, 30];
let last = xs[-1];
let before_last = xs[-2];
Indexing out of bounds is a runtime error.
Arrays are values with one element type
Arrays are regular values: you can bind them, pass them around, and return them from expressions.
let xs = [1, 2, 3];
let ys = xs;
ys[0]
All elements must have the same type. Mixing multiple element types is a type error:
[1, true] // type error
Element type inference
Ferlium infers the element type from array contents:
let ints = [1, 2, 3]; // inferred as [int]
let floats = [1.0, 2.5]; // inferred as [float]
For an empty array, add context with an annotation:
let mut out: [int] = [];
Ranges
Ranges are a compact way to describe integer sequences.
Exclusive and inclusive ranges
Use start..end for an exclusive upper bound:
let r = 1..4; // 1, 2, 3
Use start..=end for an inclusive upper bound:
let r = 1..=4; // 1, 2, 3, 4
Ranges also work in downward direction:
let r = 5..2; // 5, 4, 3
let r = 5..=2; // 5, 4, 3, 2
Parenthesize computed bounds:
let start = 0;
let r = start..(start + 3);
Iteration with for
for loops iterate over a sequence and execute a body for each element.
Iterating over ranges and arrays
Iteration works the same way for ranges and arrays:
for i in 0..3 { /* ... */ };
for x in [10, 20, 30] { /* ... */ };
Destructuring in for loops
The loop variable can destructure tuples and records:
for (i, name) in [(0, "zero"), (1, "one"), (2, "two")] {
let entry = f"{i} = {name}";
};
Accumulating with let mut
A common pattern is to keep mutable state outside the loop and update it inside:
let mut sum = 0;
for i in 1..=4 {
sum += i;
};
sum
Collecting values works the same way:
let mut out: [int] = [];
for i in 2..5 {
array_append(out, i);
};
out
For more on in-place array and string construction, see Sequence Processing.
Loop variable scope and expression result
The loop variable is local to the loop body. The for expression itself evaluates to ().
let mut count = 0;
for n in [1, 2, 3] {
count += 1;
};
count
For unconditional loops and labeled break or continue, see Control Flow and Pattern Matching.
What comes next
The next chapter introduces user-defined types, so you can give names to your own product and sum types instead of relying only on arrays, tuples, and records.