List<T>¶
Generic growable array with automatic memory management.
Import¶
# List<T> is built-in - no import required
Overview¶
List<T> is a dynamically-sized array that grows automatically as elements are added. It provides:
- Zero-capacity start: Lazy allocation until first push
- Exponential growth: Doubles capacity for amortized O(1) push
- Type-safe access: .get() returns Maybe<T> for safe bounds checking
- Iterator support: Works with foreach loops
- RAII cleanup: Automatic recursive element destruction
Construction¶
List.new() -> List<T>¶
Create empty list (zero capacity, lazy allocation).
let List<i32> nums = List.new()
List.with_capacity(i32 n) -> List<T>¶
Create list with pre-allocated capacity.
let List<string> names = List.with_capacity(100)
Query Methods¶
.len() -> i32¶
Get number of elements.
println("Size: {list.len()}")
.capacity() -> i32¶
Get allocated capacity.
println("Capacity: {list.capacity()}")
.is_empty() -> bool¶
Check if list is empty.
if (list.is_empty()):
println("Empty list")
Access Methods¶
.get(i32 index) -> Maybe<T>¶
Get element at index (bounds-checked).
match list.get(0):
Maybe.Some(value) ->
println("First: {value}")
Maybe.None() ->
println("Index out of bounds")
.pop() -> Maybe<T>¶
Remove and return last element.
match list.pop():
Maybe.Some(value) ->
println("Popped: {value}")
Maybe.None() ->
println("Empty list")
Modification Methods¶
.push(T element) -> ~¶
Append element (auto-grows capacity).
list.push(42)
list.push(100)
.insert(i32 index, T element) -> Result<~>¶
Insert element at index (shifts elements right).
# Insert at beginning
list.insert(0, 1)
# Insert in middle
list.insert(5, 42)
# Insert at end (equivalent to push)
list.insert(list.len(), 99)
Bounds: 0 <= index <= len
.remove(i32 index) -> Maybe<T>¶
Remove and return element at index (shifts elements left).
match list.remove(2):
Maybe.Some(value) ->
println("Removed: {value}")
Maybe.None() ->
println("Index out of bounds")
Bounds: 0 <= index < len
.clear() -> ~¶
Remove all elements (keeps capacity).
list.clear()
println("Length: {list.len()}") # 0
println("Capacity: {list.capacity()}") # Unchanged
Capacity Management¶
.reserve(i32 n) -> ~¶
Ensure capacity is at least n.
list.reserve(100) # Ensure space for 100 elements
.shrink_to_fit() -> ~¶
Reduce capacity to match length.
list.shrink_to_fit() # Capacity = len
Iteration¶
.iter() -> Iterator<T>¶
Create iterator for foreach loops.
foreach(value in list.iter()):
println(value)
Memory Management¶
.free() -> ~¶
Free memory and reset to empty (still usable).
list.free()
list.push(1) # OK: Can still use
.destroy() -> ~¶
Free memory and invalidate (unusable).
list.destroy()
# list.len() # ERROR CE2406: use of destroyed variable
Debugging¶
.debug() -> ~¶
Print internal state (length, capacity, elements).
list.debug() # Output: List<i32> { len: 3, capacity: 4, [1, 2, 3] }
Performance¶
push(): Amortized O(1)pop(): O(1)get(): O(1)insert(): O(n)remove(): O(n)clear(): O(n)
Implementation Details¶
- Uses
llvm.memmovefor safe overlapping memory operations - Exponential growth strategy: doubles capacity on each reallocation
- Recursive element destruction for nested structures
- Iterator support for foreach loops via
.iter()
Best Practices¶
- Use
.with_capacity()when final size is known to avoid reallocations - Use
.get()for safe access, returnsMaybe<T>instead of panicking - Call
.free()to reclaim memory early if list is no longer needed - Use
.shrink_to_fit()after batch operations to reduce memory footprint - Prefer
.pop()over.remove(len-1)for last element