Documentation menu
Language

Dicts & Sets

Dictionaries are typed key-value stores with ordered insertion. Sets are unordered collections of unique values.

Dictionaries

Every dictionary has a type annotation <key_type, value_type>. Use any for the value type when the values are mixed:

Run
// Typed dict — enforces types
let prices <string, int> = ({"apple", 2}, {"banana", 1})

// Mixed values — use any
let config <string, any> = ({"debug", true}, {"port", 8080})

// Empty dict
let cache <string, int> = ()
Two things that trip everyone on the first dict. The literal is a parenthesised list of {key, value} pairs — the JavaScript shape does not parse — and the type annotation is required to write one, not optional. The errors do not point at the real cause, so they are worth recognising:
Run
let d <string, int> = {}          // ❌ PARSER ERROR: Expected '(' to start dict literal
                                 //    The empty dict is ()

let d = ({"a", 1})               // ❌ ERROR: Entry literal {k,v} is only valid as an
                                 //    argument to a dict method
                                 //    Real cause: the <string, int> annotation is missing

let d <string, int> = ({"a", 1}) // ✅

Reading values

You can read values using bracket access or dot access. Both forms access the exact same key:

Run
let config <string, any> = ({"debug", true}, {"port", 8080}, {"first-name", "Sergio"})

out config["debug"]    // → true (bracket access)
out config.debug       // → true (dot access)

// The identifier after the dot literally represents the key.
// Keys that are not valid identifiers still require brackets:
out config["first-name"]

// Missing key returns null (typed and any-value dicts alike)
let missing = config.nope ?? "default"
out missing   // → default
Note: Accessing a missing key returns null — use ?? for a fallback. Writing a value of the wrong type into a typed dict (value type ≠ any) is a runtime error.

Nested and mixed access

When working with nested dictionaries, you can freely mix bracket and dot access:

Run
let user <string, any> = ({"name", "Sergio"})
let data <string, any> = ({"user", user})

// These four lines access exactly the same value:
out data["user"]["name"]
out data.user.name
out data["user"].name
out data.user["name"]

Adding and updating

Dot access also works for assignment. Assigning to a new key creates it:

Run
let scores <string, int> = ({"Alice", 90}, {"Bob", 75})

// Method syntax
scores.Add({"Carol", 88})   // add new key
scores.Add({"Bob", 80})     // overwrite existing key

// Assignment (both bracket and dot access modify the same key)
scores["Dave"] = 95
scores.Alice = 100          // equivalent to scores["Alice"] = 100
scores.Eve = 92             // creates the "Eve" key

out scores   // → {Alice: 100, Bob: 80, Carol: 88, Dave: 95, Eve: 92}

Key vs Dictionary Method

The resolution depends on the form of access. A property access like dic.keys accesses the key "keys", while a method call like dic.keys() invokes the dictionary method. The presence of a method does not prevent you from using a key with the same name:

Run
let dic <string, any> = ({"keys", "custom value"})

out dic.keys      // → custom value (accesses the stored key)
out dic.keys()    // invokes the method and returns an array of keys

Removing entries

scores.Remove("Bob")     // remove one key
scores.RemoveAll()       // clear everything
scores.clear()           // alias for RemoveAll

Iterating

Run
let scores <string, int> = ({"Alice", 90}, {"Bob", 75}, {"Carol", 88})

// Get all keys
let names = scores.toList()
out names   // → [Alice, Bob, Carol]

// Get all key-value pairs as a 2D array
let pairs = scores.toArray()
out pairs   // → [[Alice, 90], [Bob, 75], [Carol, 88]]

// Filter using the pairs
let top = pairs.filter(pair => pair[1] >= 85)
out top   // → [[Alice, 90], [Carol, 88]]

Sets

A Set is a collection of unique values — duplicates are silently ignored. Treat the order as an implementation detail: today it is the order you inserted in, but do not build on that.

Run
let s = new Set()
let s2 = new Set([1, 2, 3, 2, 1])   // duplicates removed
out s2   // → Set[1, 2, 3]

Working with sets

Run
let a = new Set([1, 2, 3, 4])

out a.size          // → 4
out a.has(2)        // → true
out a.has(99)       // → false

a.add(5)
a.delete(1)

out a.toArray()     // → [2, 3, 4, 5]  (order may vary)

Set operations

Run
let a = new Set([1, 2, 3, 4])
let b = new Set([3, 4, 5, 6])

out a.union(b)          // → Set{1, 2, 3, 4, 5, 6}
out a.intersection(b)   // → Set{3, 4}

// Practical: deduplicate an array
let dupes = [1, 2, 2, 3, 3, 3]
let unique = new Set(dupes).toArray()
out unique   // → [1, 2, 3]