Data & Control

Collections & Comprehensions

Select Array, Map, or Set and transform them using canonical comprehensions.

Select a collection based on the behavior your application must preserve: positional order with duplicates, key-based lookup, or element uniqueness. Comprehensions provide a concise syntax to filter and transform these collections while preserving their ordering rules.

Choose the collection first

CollectionChoose it forObservable behavior
Array<T>Ordered items, positional access, and repeated valuesIterates by increasing index and preserves duplicate values
Map<K, V>Values selected by keyKeys maintain insertion order; updating an existing key preserves its slot
Set<T>Unique valuesThe first matching value preserves the insertion slot

Run one example

Save this as collections-comprehensions.tpz:

TOPAZ
let scores = [10, 25, 10]
let labels = map { "Ada": 10, "Lin": 25 }
let unique = set { 10, 25, 10 }
let focused = [ for score in scores if score >= 20 => score * 2 ]

let first = scores[0]
let missing = scores.get(9)
let hasAda = "Ada" in labels.keys
let missingLabel = match missing {
    case Some(value) => "found {value}"
    case None => "missing"
}

print("{scores}:{unique.toArray()}:{labels.keys}")
print("{focused}:{first}:{hasAda}")
print(missingLabel)
BASH
topaz check collections-comprehensions.tpz
topaz run collections-comprehensions.tpz

It prints:

Output
[10, 25, 10]:[10, 25]:[Ada, Lin]
[50]:10:true
missing

The array retains both 10 values. The set deduplicates the second 10 and preserves the initial insertion order. Because labels.keys returns an array ordered by insertion, membership checks are written as "Ada" in labels.keys.

Read and change collections deliberately

scores[0] performs a direct indexed read. Passing a negative or out-of-range index triggers a runtime fault. scores.get(9) avoids runtime faults by returning an Option, which the example handles using match.

In-place mutation requires a mutable root binding. Declare let mut values = [...] before invoking a mutating operation such as values.push(...). Conversely, a non-mutating expression can derive a new collection from an immutable binding.

Map duplicate handling differs from Set handling. Defining duplicate literal keys produces a static error. If two keys evaluate to equal values at runtime, map construction evaluates the operands and raises a fault rather than overwriting. Map.insert serves as the explicit operation for inserting or updating key-value pairs.

Literal, loop, or comprehension?

  • Use [a, b], set { a, b }, or map { key: value } when elements are specified directly as literals.
  • Use for item in source { ... } when expressing the logic as explicit sequential steps improves readability. In statement position, it executes side effects. In expression position, it collects body evaluation results into an Array.
  • Use [ for item in source if condition => result ] when filtering and transformation fit naturally into a single expression. Replace the outer brackets with set { ... } for unique set elements or map { ... } for key-value entries.

Comprehension clauses start with for, continue with subsequent for or if keywords without commas, and conclude with =>. Clauses nest sequentially from left to right. The resulting collection is constructed only after every evaluated clause and body expression succeeds.

Common mistakes

The collection types are Array<T>, Map<K, V>, and Set<T>. [T] is not a valid collection type syntax. Set and map literals require explicit set and map keywords. #{...} and bare {key: value} syntax are invalid.

key in map is invalid. Use key in map.keys instead. A refutable pattern mismatch inside a comprehension causes a runtime fault rather than filtering items automatically. Write an explicit if clause to skip non-matching elements.

Exact boundaries

  • Array spread operations accept only another Array. Set and map literals and comprehensions do not support spread syntax.
  • Empty set {} and map {} literals require explicit type context for Set<T> or Map<K, V>.
  • Map keys and set elements must be recursively keyable.
  • Removing an entry removes its insertion slot. Reinserting the entry appends it to the end. Updating an existing map value preserves key order.
  • for loops iterate over Array, integer ranges, Set, and map.keys. Iterating over strings requires explicit scalar operations.

User-defined iteration, generators, lazy or parallel comprehensions, iterable spread, and unordered collection semantics are not supported in the current language specification.

Return to the course example in Data and Control. Refer to Patterns & Control Flow for comprehension bindings, and consult Collection Operations for available standard methods.