Sindarin provides powerful array support with type-safe operations, slicing, and modern syntax features like range literals and spread operators.
// Empty array
var arr: int[] = {}
// Array with initial values
var numbers: int[] = {1, 2, 3, 4, 5}
// Different types
var doubles: double[] = {1.5, 2.5, 3.5}
var chars: char[] = {'H', 'e', 'l', 'l', 'o'}
var bools: bool[] = {true, false, true}
var strings: str[] = {"hello", "world"}
Array literals can span multiple lines for better readability:
var numbers: int[] = {
1, 2, 3,
4, 5, 6,
7, 8, 9
}
var bytes: byte[] = {
72, 101, 108, 108, 111, // "Hello"
44, 32, // ", "
87, 111, 114, 108, 100, 33 // "World!"
}
var names: str[] = {
"Alice",
"Bob",
"Charlie"
}
Nested arrays also support multi-line formatting:
var matrix: int[][] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}
var arr: int[] = {10, 20, 30}
print(arr.length) // 3
print(len(arr)) // 3 (alternative syntax)
Adds an element to the end of the array.
var arr: int[] = {1, 2}
arr.push(3) // arr is now {1, 2, 3}
Removes and returns the last element.
var arr: int[] = {1, 2, 3}
var last: int = arr.pop() // last = 3, arr is now {1, 2}
Inserts an element at the specified index.
var arr: int[] = {1, 2, 3}
arr.insert(99, 1) // arr is now {1, 99, 2, 3}
Removes the element at the specified index.
var arr: int[] = {1, 2, 3}
arr.remove(1) // arr is now {1, 3}
Reverses the array in-place.
var arr: int[] = {1, 2, 3}
arr.reverse() // arr is now {3, 2, 1}
Creates a shallow copy of the array.
var original: int[] = {1, 2, 3}
var copy: int[] = original.clone()
copy.push(4) // original is unchanged
Returns a new array with elements from both arrays.
var a: int[] = {1, 2}
var b: int[] = {3, 4}
var c: int[] = a.concat(b) // c is {1, 2, 3, 4}
Returns the index of the first occurrence, or -1 if not found.
var arr: int[] = {10, 20, 30}
print(arr.indexOf(20)) // 1
print(arr.indexOf(99)) // -1
Returns true if the array contains the value.
var arr: int[] = {10, 20, 30}
print(arr.contains(20)) // true
print(arr.contains(99)) // false
Joins array elements into a string.
var words: str[] = {"apple", "banana", "cherry"}
print(words.join(", ")) // "apple, banana, cherry"
var nums: int[] = {1, 2, 3}
print(nums.join("-")) // "1-2-3"
Removes all elements from the array.
var arr: int[] = {1, 2, 3}
arr.clear() // arr is now {}
Access elements from the start (0-based).
var arr: int[] = {10, 20, 30, 40, 50}
print(arr[0]) // 10
print(arr[2]) // 30
Access elements from the end (-1 is last element).
var arr: int[] = {10, 20, 30, 40, 50}
print(arr[-1]) // 50
print(arr[-2]) // 40
Slicing creates a new array from a portion of the original.
start: inclusive start index (default: 0)end: exclusive end index (default: length)
var arr: int[] = {10, 20, 30, 40, 50}
arr[1..4] // {20, 30, 40}
arr[..3] // {10, 20, 30}
arr[2..] // {30, 40, 50}
arr[..] // {10, 20, 30, 40, 50} (full copy)
var arr: int[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
arr[..:2] // {0, 2, 4, 6, 8} (every 2nd element)
arr[1..:2] // {1, 3, 5, 7, 9} (odd indices)
arr[..:3] // {0, 3, 6, 9} (every 3rd element)
var arr: int[] = {10, 20, 30, 40, 50}
arr[-2..] // {40, 50} (last two)
arr[..-1] // {10, 20, 30, 40} (all but last)
arr[-3..-1] // {30, 40} (from -3 to -1, exclusive)
Range literals create integer arrays using the .. operator.
Creates an array from start to end (exclusive).
var r: int[] = 1..6 // {1, 2, 3, 4, 5}
var r2: int[] = 0..10 // {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
Ranges can be used inside array literals.
var arr: int[] = {0, 1..4, 10} // {0, 1, 2, 3, 10}
var arr2: int[] = {1..3, 10..13} // {1, 2, 10, 11, 12}
The spread operator (...) expands an array inside an array literal.
var original: int[] = {1, 2, 3}
var copy: int[] = {...original} // {1, 2, 3}
var arr: int[] = {1, 2, 3}
var extended: int[] = {0, ...arr, 4, 5} // {0, 1, 2, 3, 4, 5}
var a: int[] = {1, 2}
var b: int[] = {3, 4}
var merged: int[] = {...a, ...b} // {1, 2, 3, 4}
var arr: int[] = {1, 2, 3}
var mixed: int[] = {...arr, 10..13} // {1, 2, 3, 10, 11, 12}
Arrays can hold lambda/function types, but parentheses are required to disambiguate the syntax.
Without parentheses, the syntax is ambiguous:
// AMBIGUOUS - don't do this!
var arr: fn(str, str): str[] // Does this mean:
// 1. Lambda returning str[] ?
// 2. Array of lambdas returning str ?
// Array of lambdas (parentheses required)
var handlers: (fn(str): int)[] = {}
var transforms: (fn(int, int): int)[] = {}
// Lambda returning an array (no parentheses needed - this is the default interpretation)
var getNames: fn(): str[] = () => { return {"Alice", "Bob"} }
The parser binds [] to the innermost type first. So:
fn(str): str[]= function returningstr[](array binds to return type)(fn(str): str)[]= array of functions returningstr(array binds to whole function type)
// Declare array of lambdas
var operations: (fn(int, int): int)[] = {}
// Add lambdas to the array
var add: fn(int, int): int = (a: int, b: int) => a + b
var mul: fn(int, int): int = (a: int, b: int) => a * b
operations.push(add)
operations.push(mul)
// Call lambdas from the array
var result1: int = operations[0](10, 5) // 15
var result2: int = operations[1](10, 5) // 50
If the compiler detects a potentially ambiguous declaration, it may emit an error:
error: Ambiguous array declaration. Use parentheses to clarify:
- For array of functions: (fn(str): str)[]
- For function returning array: fn(str): str[]
Arrays can be compared for equality.
var a: int[] = {1, 2, 3}
var b: int[] = {1, 2, 3}
var c: int[] = {1, 2, 4}
print(a == b) // true
print(a == c) // false
print(a != c) // true
var arr: int[] = {10, 20, 30}
for x in arr =>
print($"value: {x}\n")
// Calculate sum
var sum: int = 0
for n in arr =>
sum = sum + n
print($"Sum: {sum}\n")
fn main(): void =>
// Create array with range
var numbers: int[] = 1..6
print("Initial: ")
print(numbers)
print("\n")
// Add more elements with spread
var extended: int[] = {0, ...numbers, 6..9}
print("Extended: ")
print(extended)
print("\n")
// Slice and iterate
var middle: int[] = extended[2..6]
var sum: int = 0
for n in middle =>
sum = sum + n
print($"Sum of middle elements: {sum}\n")