Arrays

Ordered, mutable, heterogeneous sequences with a large built-in method set.

Summary

Mutating methods (.push(), .pop(), .sort(), .reverse()) modify in-place and return null. Non-mutating variants (.sorted(), .reversed()) return a new array. Negative indexing counts from the end; out-of-bounds throws an IndexError. Use .get(i) for a nullable lookup. The repeat syntax [val; n] creates an array with n copies of val. Spread with [...arr, x] builds a new array.

Canonical

var arr = [1, 2, 3, 4, 5]

-- access
arr[0]                           -- 1
arr[-1]                          -- 5 (negative indexing)
arr[100]                         -- IndexError: out of bounds
arr.get(100)                     -- null (explicit nullable lookup)
arr.get(100, "missing")          -- "missing" (default fallback)

-- mutating methods (modify in-place, return null)
arr.push(6)                      -- append element
arr.pop()                        -- remove and return last element
arr.reverse()                    -- reverse in-place
arr.sort()                       -- sort in-place (ascending)
arr.sort(fn(a, b) { a - b })    -- sort with comparator

-- non-mutating methods (return new values)
arr.len()                        -- length
arr.first()                      -- first element or null
arr.last()                       -- last element or null
arr.is_empty()                   -- true if length is 0
arr.contains(3)                  -- true
arr.index_of(3)                  -- index or -1
arr.join(", ")                   -- "1, 2, 3, 4, 5"
arr.slice(1, 3)                  -- [2, 3]
arr.reversed()                   -- new reversed array
arr.sorted()                     -- new sorted array
arr.sort_by(fn(x) { -x })       -- new array sorted by key function
arr.flatten()                    -- flatten one level
arr.zip([10, 20, 30])            -- [(1, 10), (2, 20), (3, 30)]
arr.enumerate()                  -- [(0, 1), (1, 2), (2, 3), ...]
arr.step(2)                      -- every n-th element (alias: stride)

-- higher-order methods
arr.map(fn(x) { x * 2 })
arr.filter(fn(x) { x > 2 })
arr.reduce(fn(acc, x) { acc + x }, 0)   -- reduce(fn, init)
arr.fold(0, fn(acc, x) { acc + x })     -- fold(init, fn)
arr.find(fn(x) { x > 3 })       -- first match or null
arr.any(fn(x) { x > 4 })        -- true if any element matches
arr.all(fn(x) { x > 0 })        -- true if all elements match

-- aggregates
arr.sum()                        -- sum of numbers
arr.min()                        -- minimum value
arr.max()                        -- maximum value

-- repeat syntax
let zeros = [0; 10]              -- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

-- spread
let combined = [...arr, 6, 7, 8]

`reduce` vs `fold`: Same operation, different argument order. reduce(fn, init) puts the function first; fold(init, fn) puts the initial value first.

Mutating vs non-mutating: .reverse() and .sort() modify in-place and return null. .reversed() and .sorted() return a new array.