Browse documentation
Data structures

List

Ordered heterogeneous storage, mutation, compatible sorting, and time and space complexity.

List is a built in, mutable sequence. It preserves element order and duplicate values, provides indexed access, and supports elements with different concrete runtime types. Its native storage is a growable array of values.

Declaration and construction

List requires no import and no type argument. The constructor accepts zero or more positional values. Constructor arguments are evaluated once in source order. Named constructor arguments are not supported.

aner
let empty: List = List()
let values = List(10, "hello", 1.5, true, null)
values.append("last")
print(values)

Output:

text
List(10, "hello", 1.5, true, null, "last")

List may be used in parameters, fields, return types, checked casts, and concrete arguments to user defined generic classes. List<Int64> and other typed specializations are not supported. List is a reserved built in name.

A binding inferred as List retains that static type. Use an explicit Any binding when its value must later have a different concrete type. A let binding prevents rebinding and permits mutation of the referenced List.

Element contract

An element may be an Int64, Float64, String, Bool, null, user object, native value, or nested collection. Unit () is not a valid element.

get, get_or, pop, and remove_at return static type Any. type_of(value) identifies its concrete runtime type. cast<Type>(value) checks that type without converting it. For example, an Int64 value cannot be cast to Float64; Float64(cast<Int64>(value)) performs an explicit numeric conversion.

aner
let values = List(10, "hello")
print(type_of(values.get(0)))
print(cast<Int64>(values.get(0)) + 5)

Output:

text
Int64
15

Indexing

Indices have type Int64 and are zero based. Negative indices do not address elements from the end.

  • get, set, and remove_at require 0 <= index < len().
  • insert requires 0 <= index <= len(); the final position appends.
  • get_or returns its fallback for an index outside the valid range, including a negative index.
  • pop requires a nonempty List.

All method arguments are evaluated before the method executes. A get_or fallback expression is evaluated even when the requested element exists.

Equality and membership

contains uses strict runtime equality. Scalars compare by value only when their concrete types match. Null compares equal to null. User objects and nested collections compare by reference identity. Integer 1, float 1.0, Boolean true, and String "1" are distinct values for membership.

Membership does not recursively compare nested collections. If a comparison reaches two same type native composite values without an equality operation, such as two Tensors, contains reports R2901. Values with different concrete runtime types compare unequal. NaN follows numeric equality and does not compare equal to itself.

A List itself compares by reference identity. An alias equals the original List; a separate List or copy() has a different identity. Comparing differently typed values requires compatible static types, for example an Any operand.

Aliases and copies

Assignment shares the List reference. copy() creates an independent outer List, copying owned scalar payloads and retaining shared references to nested collections and user objects. Native payloads preserve their existing copy or alias behavior. Copying does not recursively clone a nested graph.

aner
let child = List(1)
let original = List(child)
let copied = original.copy()
cast<List>(copied.get(0)).append("shared")
copied.append("copy only")
print(child.len())
print(original.len())
print(copied.len())

Output:

text
2
1
2

Methods

Methods accept positional arguments or named arguments with the labels below. Named arguments select parameter destinations without changing expression evaluation order. A Unit result cannot be chained.

MethodResultContract
append(value: Any)UnitAppend one value.
clear()UnitRemove all elements and release List capacity.
contains(value: Any)BoolTest strict runtime equality against the elements.
copy()ListReturn a new shallow outer List.
extend(other: List)UnitAppend the other List's current elements in order.
get(index: Int64)AnyReturn the element at a valid index.
get_or(index: Int64, default: Any)AnyReturn the element or the fallback for an invalid index.
insert(index: Int64, value: Any)UnitInsert at the given position and shift subsequent elements.
is_empty()BoolReturn whether the List has no elements.
len()Int64Return the live element count.
pop()AnyRemove and return the final element.
remove_at(index: Int64)AnyRemove and return the indexed element, shifting subsequent elements.
set(index: Int64, value: Any)UnitReplace the indexed element.
sort()UnitStably reorder supported elements into ascending order.

extend snapshots the source elements before appending. Extending a List with itself repeats its original contents once.

Sorting

sort() mutates the existing List. Every alias observes the resulting order. Sorting is stable: elements that compare equal retain their relative order and concrete runtime types.

Element groupAscending order
Bool onlyfalse before true.
Int64, Float64, or a mixture of bothNumeric order without converting stored values or rounding large Int64 values to Float64.
String onlyCase sensitive lexicographic order of encoded bytes.

Numeric ordering places negative infinity first and positive infinity last. Equal Int64/Float64 numeric values and positive/negative zero retain their original relative order. Numeric ordering does not change the strict equality contract used by membership.

String ordering does not apply locale rules, natural number ordering, or Unicode normalization. Bool values cannot be mixed with numeric values.

An empty List may be sorted. Unsupported elements are rejected even in a one element List. Null, NaN, nested collections, user objects, native composites, and incompatible mixtures such as an Int64 with a String have no default sort order. No custom comparator or descending order argument is currently supported.

Sorting validates every element before mutation. Validation or allocation failure leaves the List contents and order unchanged. A runtime failure in a persistent notebook still clears the native Session according to the normal Session error contract.

The implementation validates the elements, stably merge sorts an index permutation, and moves values into the resulting order. It does not deep copy owned String payloads or traverse nested graphs.

Time and space complexity

Let n be the receiver's live length, m the other List's length, and c the allocated capacity. Bounds assume bounded cost values. Space below is additional auxiliary, result, or new persistent storage beyond the existing List and evaluated arguments.

Constructor or methodTimeAdditional space
List(...values: Any)O(n) for n inputsO(n) new List.
append(value: Any)Amortized O(1); worst O(n) on growthO(1) new slot; worst O(n) transient growth buffer.
clear()O(n)O(1) auxiliary; capacity and contents are released.
contains(value: Any)O(n) worstO(1).
copy()O(n)O(n) new shallow List.
extend(other: List)O(m) amortized; worst O(n + m) on growthO(m) new slots and O(m) auxiliary snapshot; up to O(n + m) transient growth storage.
get(index: Int64)O(1)O(1) result, plus copied payload bytes.
get_or(index: Int64, default: Any)O(1)O(1) result, plus copied payload bytes.
insert(index: Int64, value: Any)O(n) worst; final position amortized O(1)O(1) new slot; worst O(n) transient growth buffer.
is_empty()O(1)O(1).
len()O(1)O(1).
pop()O(1)O(1) auxiliary; the removed owned payload transfers to the result.
remove_at(index: Int64)O(n) worst; final position O(1)O(1) auxiliary; the removed owned payload transfers to the result.
set(index: Int64, value: Any)O(1)O(1) replacement, plus stored payload bytes.
sort()O(n) validation and O(n log n) sorting for n >= 2; O(1) for n <= 1O(n) auxiliary; no new List or deep payload copy.

The List retains O(c) slots plus owned payload bytes. Geometric capacity growth provides the amortized append bound. pop and remove_at retain capacity; clear releases it.

A String of p bytes can add O(p) time and storage when copied or stored. A String comparison can inspect the shared prefix; String sorting performs O(n log n) comparisons and has worst case time O(n log n · (1 + k)) for maximum String length k. The auxiliary sorting space remains O(n). Native value copies retain their own payload costs. Nested collection and object references are shallow handles.

These operation bounds exclude parsing, argument evaluation, heap reference validation, automatic tracing, and display. The heap identity registry has expected constant time hash lookup; its collision cost depends on the total heap size. With h outstanding heap objects, s traced value slots, and g roots, tracing takes expected O(h + s + g) time and O(h) auxiliary space; hash collisions can increase the time.

Error behavior and resource limits

ConditionDiagnostic
Invalid index for strict access, removal, or insertion; pop on an empty ListR2901
Unsupported or incompatible sort contents; NaN in sortingR2901
Unsupported same type native equality encountered by containsR2901
Collection resource limit failureR2901
Host memory allocation failure in command line executionE9003
Wrong static argument type or arity; named constructor arguments; typed List specialization; Unit payloadE1002
Failed checked cast or unsupported Any equality operatorR1002

A native runtime failure clears the entire notebook Session. A parsing or type checking failure preserves previous Session state. Saved notebook outputs do not reconstruct live Lists after a restart.

The execution heap permits 16,384 outstanding heap objects, 262,144 outstanding value slots, and 16 MiB of directly stored collection String bytes. These limits are shared with other heap backed values. Each List element occupies one slot. Every owned String copy contributes its stored byte count; a nested reference occupies one slot and does not recursively duplicate its referenced storage.

The limits do not constitute a whole process RAM quota. They exclude native payload buffers, heap metadata, retained source, allocator overhead, and ordinary user class String fields. Native values retain their own operation limits.

Unreachable objects and cycles are reclaimed after a successful shared session cell. There is no collection during a cell, so repeated temporary allocations can reach the limits before completion. clear and removals release direct element and String accounting; unreachable nested objects are reclaimed by the next successful session collection.

Display is a bounded preview: at most 50 entries per collection, eight nested collection levels, and 8,192 output bytes. Strings are quoted and escaped. Cycles and omitted contents use markers such as <cycle:List>, <depth-limit:List>, and .... Display is not serialization; its state uses O(depth) active path storage and O(output bytes) result storage.

Examples

Indexed mutation

aner
let tasks = List("read", "write")
tasks.insert(index: 1, value: "check")
tasks.set(index: 0, value: "open")
print(tasks.remove_at(1))
print(tasks.pop())
print(tasks.get_or(index: 99, default: "no task"))

Output:

text
check
write
no task

Numeric sorting

aner
let numbers = List(3, 1.5, 1, -2.0)
numbers.sort()
print(numbers)

Output:

text
List(-2.0, 1, 1.5, 3)

String sorting and traversal

aner
let words = List("pear", "apple", "banana")
words.sort()
var index = 0
while index < words.len() {
    print(cast<String>(words.get(index)))
    index = index + 1
}

Output:

text
apple
banana
pear

Traversal currently uses while and explicit methods. List literals, bracket indexing, general for loops, and iterator APIs are not supported.

In VS Code, the list and listsort snippets provide Aner examples. Signature help describes parameters, result types, complexity, and ordering constraints. The editor and native executable must support the same API.

Aner documentation · Reference and guides