Array
Fixed length typed storage, mutation, sorting, searching, numerical operations, and time and space complexity.
Array<T> is a built in, fixed length, one dimensional data structure with an explicit scalar element type. Construction initializes every element. Indexed mutation is permitted; length and capacity remain fixed. No import is required.
Construction
let scores = Array<Int64>(size: 4, fill: 0)
scores.set(index: 0, value: 30)
scores.set(1, 10)
scores.set(2, 20)
scores.sort()
print(scores.to_list())
print(scores.find(20))The output is List(0, 10, 20, 30), followed by 2. Constructor arguments are size: Int64 and fill: T. Size must be between 0 and 1,000,000 inclusive. Empty arrays are valid. capacity() always equals len().
The element type must be Int64, Float64, Bool, or String. Type arguments are required. Array<Any>, nullable elements, nested arrays, and user object element types are unsupported. Method arguments require the exact declared type; an Int64 value requires explicit conversion before storage in a Float64 array. Bool is a separate type. Float64 elements and computed array results must be finite.
let values = Array<Float64>(size: 3, fill: 0.0)
values.set(0, Float64(2))Storage and ownership
Int64 and Float64 elements occupy contiguous eight byte native slots. Bool occupies one byte per element. String elements use contiguous native descriptors with separately owned text payloads; text is not stored as a packed character matrix. Elements do not carry individual Any tags.
A let binding prevents rebinding; it does not prevent element mutation. Assignment shares object identity and storage. copy() returns independent storage. slice(start, stop) returns an independent same type array for the half open interval; it is not a view. Equality compares object identity, not element contents.
let original = Array<Int64>(size: 2, fill: 9)
let alias = original
let independent = original.copy()
alias.set(0, 3)
print(original.get(0))
print(independent.get(0))The output is 3, then 9. Arrays may be held in Any, collection values, and user class fields. cast<Array<Int64>>(value) validates the family and dtype without conversion or copying.
reshape(shape: List) produces a new NDArray descriptor sharing the fixed buffer. It preserves dtype and row major element order. The supplied shape must contain 1 to 8 Int64 dimensions from 0 through 1,000,000 with the same total element count; dimension inference is unavailable. Writes through either descriptor are visible through the other. Sorted search metadata remains correct after a shared buffer mutation.
Methods and complexity
Let n be the element count, m the length of a copied slice, and r the rank of a reshape result. Persistent scalar storage is O(n). The space column distinguishes additional auxiliary storage from newly allocated result storage. Empty input operations include constant work.
| Method | Result | Time | Additional space |
|---|---|---|---|
Array<T>(size: Int64, fill: T) | Array<T> | O(n) | O(n) result |
capacity(), len() | Int64 | O(1) | O(1) |
contains(value: T) | Bool | O(log n) sorted; O(n) otherwise | O(1) |
copy() | Independent Array<T> | O(n) | O(n) result |
fill(value: T) | Unit | O(n) | O(1), subject to String qualification below |
find(value: T) | First matching Int64 index, or −1 | O(log n) sorted; O(n) otherwise | O(1) |
get(index: Int64) | T | O(1) | O(1), plus any returned String payload |
is_empty(), is_sorted() | Bool | O(1) | O(1) |
reshape(shape: List) | Shared NDArray<T> descriptor | O(r) | O(r) metadata; no element copy |
reverse() | Unit | O(n) | O(1) |
set(index: Int64, value: T) | Unit | O(1) | O(1), subject to String qualification |
slice(start: Int64, stop: Int64) | Independent Array<T> | O(m) | O(m) result |
sort() | Unit | O(n log n), worst case | O(1) |
to_list() | Independent List | O(n) | O(n) result |
Length changing methods, including append, insert, remove_at, pop, resize, clear, and reserve, are unavailable and rejected during checking.
Sorting and searching
sort() applies in place, unstable heapsort in ascending order. Int64 and Float64 use numerical order. Bool orders false before true. String uses case sensitive lexicographic order of encoded bytes, without locale rules, natural number order, or Unicode normalization. Positive and negative floating zero compare equally. A custom comparator and descending parameter are unavailable.
The runtime maintains an exact count of adjacent inversions. is_sorted() therefore requires O(1) time; empty and singleton arrays are sorted. When the count is zero, find and contains use lower bound binary search. Otherwise they use linear search. No search tree is allocated. Mutations immediately update the search strategy. Duplicate values return the first matching index.
let items = Array<Int64>(size: 3, fill: 0)
items.set(0, 30)
items.set(1, 10)
items.set(2, 20)
print(items.is_sorted())
print(items.find(20))
items.sort()
print(items.is_sorted())
print(items.find(20))The output is false, 2, true, 1.
Numerical methods
Numerical methods are available for Int64 and Float64 elements. Binary array operands require Array<T> with the same dtype and length. Arithmetic results are independent arrays; inputs remain unchanged.
| Method | Result | Time | Additional space |
|---|---|---|---|
add(other: Array<T>), sub(other: Array<T>), mul(other: Array<T>) | Array<T> | O(n) | O(n) result |
argmax(), argmin() | First tied Int64 index | O(n) | O(1) |
cumsum() | Array<T> | O(n) | O(n) result |
div(other: Array<Float64>): Float64 only | Array<Float64> | O(n) | O(n) result |
dot(other: Array<T>) | T | O(n) | O(1) |
max(), min(), sum() | T | O(n) | O(1) |
mean(), std(), variance() | Float64 | O(n) | O(1) |
scale(factor: T) | Array<T> | O(n) | O(n) result |
to_float() | Array<Float64> | O(n) | O(n) result |
to_tensor(rows: Int64, cols: Int64): Float64 only | Detached Tensor | O(n) | O(n) result |
Empty sum and dot return typed zero. Empty cumsum and elementwise operations are valid. Mean, standard deviation, variance, extrema, and their indices require nonempty input. Variance and standard deviation use the population definition, dividing by n; no sample statistic parameter is available.
Int64 intermediate arithmetic is checked. Overflow fails even if a later term could cancel it. Division requires Float64 operands; zero divisors and nonfinite results fail. to_float() is explicit and detached; large integer values may round. Mean and population statistics use scaled floating computation to reduce avoidable overflow, subject to representable range and roundoff. A standard deviation can be representable while its variance is not.
to_tensor requires positive dimensions whose product equals n. It copies values into a detached row major Tensor; the source array does not record gradients. Inference of the bridge result needs no import. Explicit Tensor annotations and Tensor operations require the appropriate numerical module.
let x = Array<Float64>(size: 3, fill: 0.0)
x.set(0, 1.0)
x.set(1, 2.0)
x.set(2, 3.0)
let y = x.scale(factor: 2.0)
print(x.sum())
print(x.dot(y))
print(x.cumsum().to_list())
let detached = x.to_tensor(rows: 1, cols: 3)String complexity
Scalar complexity rows apply directly to Int64, Float64, and Bool. String operations additionally account for bytes copied, released, or compared. Persistent String storage is O(n + B), where B is total owned text bytes. get returns an owned String copy and therefore includes its text length in time and result space. set, copy, slice, and conversions include copied payload bytes.
String fill constructs an entire replacement buffer before mutation: O(n + copied/released text bytes) time and O(n + new text bytes) temporary space. Searching performs O(log n) or O(n) comparisons; each comparison can inspect a common prefix. For maximum String length k, sorting has O(n log n · (1 + k)) worst case time and O(1) auxiliary descriptors.
Bounds and errors
Indices are zero based. get and set require 0 <= index < n; negative indices are unsupported. Slices require 0 <= start <= stop <= n.
Invalid size, out of bounds indices, nonfinite values, integer overflow, incompatible operands, invalid reshape, and array allocation quota exhaustion report source located R3001. Unsupported types, methods, and statically known dtype errors are detected before execution. Host allocation failure uses the CLI's E9003 insufficient memory handler. Failed native mutation does not partially change an existing array. A persistent session runtime error clears session state.
Each buffer permits at most 1,000,000 elements. Typed array buffers share a 64 MiB logical allocation budget in one heap, including capacity slots, String descriptors, and owned String payloads. Shared reshape buffers are charged once. The budget is separate from collection slots and Tensor limits, and excludes allocator overhead, transient replacement buffers, and total process memory. Unreachable buffers are reclaimed after successful persistent session cells; a retained reshape descriptor keeps its shared buffer alive.
Development inspection
Development observations show dtype, length, capacity, sorted status, and up to 16 copied elements. Production omits recording while preserving validation and algorithms. The report directory must be new:
aner examples/arrays_basic.aner --dev artifacts/array-inspectionExamples and related references
The array construction tutorial, numerical tutorial, VS Code array notebook, and Jupyter array notebook exercise the typed array APIs. Use aner check before execution when validating a source file.
- DynamicArray: capacity managed typed sequences.
- NDArray: fixed multidimensional shapes and broadcasting.
- Tensor: numerical computation and differentiation.
- Development mode: bounded reports and notebook inspection.