Array Methods¶
Built-in methods for fixed-size and dynamic arrays.
Import¶
Arrays are built-in types and require no import. For dynamic array construction from literals, arrays are available by default.
let i32[5] fixed = [1, 2, 3, 4, 5] # Fixed-size array
let i32[] dynamic = from([1, 2, 3]) # Dynamic array
Overview¶
Sushi provides two array types:
- Fixed arrays (T[N]): Stack-allocated, compile-time size
- Dynamic arrays (T[]): Heap-allocated, runtime size
Both types share common methods, while dynamic arrays have additional memory management methods.
Common Methods (Fixed and Dynamic)¶
.len() -> i32¶
Get number of elements.
let i32[5] arr = [1, 2, 3, 4, 5]
println(arr.len()) # 5
.get(i32 index) -> Maybe<T>¶
Bounds-checked access (returns Maybe<T>).
match arr.get(2):
Maybe.Some(value) ->
println("Value: {value}")
Maybe.None() ->
println("Index out of bounds")
# Or use error propagation
let i32 value = arr.get(2)??
Note: Direct indexing arr[index] is also available but throws RE2020 runtime error on out-of-bounds.
.iter() -> Iterator<T>¶
Create iterator for foreach loops.
foreach(n in arr.iter()):
println(n)
.hash() -> u64¶
Compute hash of array contents.
let u64 h = arr.hash()
Limitation: Nested arrays cannot be hashed.
.fill(T value) -> ~¶
Fill all elements with value (in-place).
arr.fill(0) # All elements become 0
.reverse() -> ~¶
Reverse array elements (in-place).
let i32[5] arr = [1, 2, 3, 4, 5]
arr.reverse() # [5, 4, 3, 2, 1]
Dynamic Array Only¶
.push(T element) -> ~¶
Append element to end (grows array).
let i32[] arr = from([1, 2, 3])
arr.push(42)
# arr is now [1, 2, 3, 42]
.pop() -> T¶
Remove and return last element (returns the element's zero value if the array is empty).
let i32 last = arr.pop()
println("Popped: {last}")
.capacity() -> i32¶
Get allocated capacity.
println("Capacity: {arr.capacity()}")
.clone() -> T[]¶
Deep copy of array.
let i32[] copy = arr.clone()
.free() -> ~¶
Clear and reset to zero capacity (still usable).
arr.free()
arr.push(1) # OK: Can still use
.destroy() -> ~¶
Free memory and invalidate (unusable).
arr.destroy()
# arr.len() # ERROR CE2406: use of destroyed variable
Byte Array Only (u8[])¶
.to_string() -> string¶
Zero-cost UTF-8 conversion.
let u8[] bytes = from([72 as u8, 105 as u8])
let string text = bytes.to_string() # "Hi"
Memory Management¶
Fixed Arrays¶
- Stack-allocated
- Size known at compile-time
- Automatic cleanup when out of scope
- Cannot grow or shrink
Dynamic Arrays¶
- Heap-allocated
- Size determined at runtime
- RAII cleanup with recursive element destruction
- Move semantics (ownership transfer)
- Can grow with
.push()
Safe vs Unsafe Access¶
let i32[] arr = from([1, 2, 3])
# Safe: Returns Maybe<T>
let Maybe<i32> safe = arr.get(0)
let i32 value = arr.get(0)?? # Error propagation
# Unsafe: Direct indexing (throws RE2020 if out of bounds)
let i32 direct = arr[0]
Best practice: Use .get() for safety, use [index] for idiomatic access when bounds are known.
Performance¶
- Access (
.get(),[index]): O(1) - Push (
.push()): Amortized O(1) - Pop (
.pop()): O(1) - Fill (
.fill()): O(n) - Reverse (
.reverse()): O(n) - Hash (
.hash()): O(n) - Clone (
.clone()): O(n)
Implementation Details¶
- Dynamic arrays use exponential growth strategy
- Runtime bounds checking for all access methods
- RAII cleanup recursively destroys nested structures
- Move semantics prevent use-after-move errors
.destroy()marks array as invalid at compile-time
Best Practices¶
- Use fixed arrays when size is known at compile-time
- Use dynamic arrays for runtime-sized collections
- Prefer
.get()over direct indexing for safety - Use
.clone()sparingly (deep copy overhead) - Call
.free()to reclaim memory early if array is no longer needed - Use
.iter()for idiomatic iteration in foreach loops - Prefer
List<T>over dynamic arrays for complex operations
Example Usage¶
fn main() i32:
# Fixed array
let i32[3] fixed = [1, 2, 3]
println("Fixed length: {fixed.len()}")
# Dynamic array
let i32[] dynamic = from([1, 2, 3])
dynamic.push(4)
dynamic.push(5)
# Safe access
match dynamic.get(2):
Maybe.Some(value) ->
println("Element 2: {value}")
Maybe.None() ->
println("Out of bounds")
# Iteration
foreach(n in dynamic.iter()):
println(n)
# In-place operations
dynamic.reverse()
dynamic.fill(0)
# Cleanup
dynamic.free()
return Result.Ok(0)