Skip to content
kata / a language workbench

Collections

Arr[T] and Map[K, V] arrive through the prelude. Both are implemented in KataScript. Use direct bindings when growing or mutating them; their current storage and lifetime behavior has known limits.

[value, ...] creates an array and infers the element type. Elements must be compatible. To construct an empty array of a known type, use Arr[T].new().

let values = Arr[Int].new()
values.push(10)
values.push(20)
values[0] = 11
print(values.len)
print(values.get(0).unwrap_or(0))
print(values.pop().unwrap_or(0))
OperationContract
Arr[T].new()Create an empty array of T
array.lenNumber of live elements; a field, with no parentheses
array.push(value)Append a value of the element type
array.pop()Remove the last value; return Opt[T], absent if empty
array.get(index)Return Opt[T], absent if the index is out of bounds
array.set(index, value)Replace an existing element; return whether it existed

Array indices are zero-based Int values. Negative indices are out of bounds; they do not count backward from the end. set does not append.

Map[K, V].new() creates an empty map with explicit key and value types. There is no map literal. Keys need hashing and equality behavior; the examples use Str keys.

let scores = Map[Str, Int].new()
scores.set("Ada", 42)
scores["Lin"] = 37
print(scores.has("Ada"))
print(scores.get("Sam").unwrap_or(0))
print(scores.len())
OperationContract
map.set(key, value)Insert a new key or replace its value
map.get(key)Return Opt[V], absent when the key is missing
map.has(key)Return whether the key exists
map.del(key)Remove a key; return whether it existed
map.len()Number of entries; a method, with parentheses

Repeated insertion/deletion has a known corruption defect, and float keys have equality/hash edge cases. The documented examples avoid both patterns.

collection[key] invokes GetItem through get_item. collection[key] = value invokes SetItem through set_item. Array indexing assumes the position exists; map indexing assumes the key exists. A failed read stops evaluation. Use get(...).unwrap_or(default) or match when absence is expected.

Array assignment replaces an existing element. Map assignment inserts or replaces an entry. Bin also supports read indexing and returns a Byte. Tuples use positional access such as tuple.0, rather than the collection indexing protocol.

for pattern in collection { ... } obtains an iterator through to_iter() when available, then calls next() until it returns Opt[T].Non. Each Opt[T].Val(value) produces one loop iteration. Arrays yield elements; maps yield (key, value) tuples.

let scores = Map[Str, Int].new()
scores["Ada"] = 42
scores["Lin"] = 37
let total = 0
for (_, score) in scores { total = total + score }
print(total)

Map order is not a stable output contract. Traverse a separate sequence of keys when ordering matters. Do not mutate a collection while iterating over it. A custom iterable implements ToIter[T], and its iterator implements Iter[T]; see the custom iterator example.

Method help is name-based. A name does not establish a particular receiver type: get can mean an array position or map key, and user types can define their own method with the same name. new() is a library convention for static constructors, not a keyword. len is especially easy to confuse: arrays expose a field, while strings, binary values, tuples, and maps expose methods.

Assigning a collection to another name does not promise a deep copy. Keep one binding responsible for growth and avoid treating Copy or Dupe as a completed ownership guarantee.