List[T], normally written []T, is an owned growable sequence.
mut names: []string = ["Ada", "Grace"]
names.add("Lin")List.new[T](capacity) and List.with_capacity[T](capacity) create empty
lists. The capacity argument reserves storage without changing the length.
List.copy(other, capacity) creates an independent list and never chooses a
capacity smaller than the source length.
mut queue := List.with_capacity[Job](64)
copy := List.copy(queue)The empty list literal [] relies on context or later use to infer its element
type. Add an annotation when there is no such context.
Access
first: string? = names.first()
third: string? = names.get(2)get, first, and last are safe and optional. set overwrites an existing
index on a mutable receiver; it is a no-op when the index is outside the
current length and never extends the list. Use add to append.
| Method | Out-of-range behavior |
|---|---|
get(index) |
None |
first(), last() |
None for an empty list |
set(index, value) |
No operation |
get_unchecked(index) |
Caller must prove the index is valid |
get_unchecked skips bounds checks and belongs only in low-level code with an
explicit proof such as index < values.len().
Inspection methods include size, len, capacity, is_empty, and
is_not_empty. size and len are aliases. reserve(additional) ensures
room for that many more elements; it does not change the logical length.
Transformations
lengths := names.map(name => name.length())
long_names := names.filter(name => name.length() > 3)
total := lengths.fold(0, (sum, value) => sum + value)Lists provide map, filter, flat_map, fold, reduce, scan, any,
all, none, find, find_index, count, and enumerate.
fold and reduce both take an explicit initial accumulator. scan returns
every running accumulator and includes the initial value as its first element.
any, all, and none short-circuit once the answer is known.
Aggregate methods include sum, sum_of, average, min, max, and
key-based min_by, max_by, min_of, and max_of. Empty min/max
operations return None. Trait bounds make requirements explicit: numeric
aggregates need Numeric, while extrema and sorting need Comparable.
Ordering
sorted, sorted_descending, sorted_by, and
sorted_by_descending return new lists. reversed is an iterator, while
shuffled returns a new list. The source list is not reordered in place.
by_name := users.sorted_by(user => user.name)
for user in users.reversed() {
visit(user)
}Windows
take, take_last, take_while, skip, skip_last, and skip_while
produce owned lists. slice(range) returns Slice[T]?, a borrowed view:
middle := names.slice(1..3)Ranges are half-open. slice returns None when start > end or the end lies
past the list length. A Slice[T] borrows the parent storage and supports safe
access, nested slicing, in-place replacement, and to_list() for an owned
copy.
chunked(size) creates consecutive chunks. windowed(size, step) creates
overlapping or strided windows. Keep size and step positive; invalid values
are not a substitute for an empty-result policy.
Reshaping
| Operation | Result |
|---|---|
group_by(key) |
Map[K, []T] |
partition(predicate) |
(matching, non_matching) |
associate(pair) |
Map from returned key/value tuples |
associate_by(key) |
Map keyed by each element; later duplicates win |
zip(other) |
Pairs up to the shorter list |
flatten() |
Concatenates a list of lists |
distinct, distinct_by |
Preserve the first occurrence |
plus, plus_all, minus, and related methods return a new list. add,
set, reserve, and clear mutate the receiver. Set-like intersect,
union, subtract, and distinct require values with compatible equality and
hashing.
join(separator) stringifies elements. join_of(separator, format) formats
each element explicitly before joining.
Iteration
Lists implement Iterable[T]:
for name in names {
println(name)
}See Iteration for iterator adapters and Sequences for list/slice type syntax.