What operations does Dict support in EK9?
← Getting Started · Ref: Q90
Dict supports a rich set of operations beyond basic creation and lookup. This covers containment checks, key/value iterators, merging, copying, comparison, and conversions.
CONTAINS (KEY CHECK)
Three equivalent ways to check if a key exists:
ages contains "Alice" operator syntax "Bob" is in ages natural language syntax "Zara" is not in ages negated form
These check keys, not values.
KEYS AND VALUES ITERATORS
keyIter <- ages.keys() iterator over all keys valIter <- ages.values() iterator over all values
These return iterators (not lists). Use in while loops:
while keyIter? stdout.println(keyIter.next())
MERGING DICTS
+ creates a new merged dict (originals unchanged):
combined <- dict1 + dict2
:~: merge operator (mutates the left-hand side):
dict1 :~: dict2
When keys overlap, the right-hand side values win.
COPY AND REPLACE
:=: deep copy:
copied :=: original
:^: replace contents entirely:
target :^: source
COMPARISON
dict1 == dict2 equal if same key-value pairs dict1 <> dict2 not equal
STRING AND JSON CONVERSION
$ages string representation $$ages JSON object representation
The $$ operator converts Dict to JSON with keys as JSON keys and values as JSON values.
HASHCODE
hash <- #? ages integer hashcode
EMPTY DICT IS SET (NOT UNSET)
CRITICAL: An empty dict IS set. Creating Dict() of (K, V) gives you a valid, set, empty dict. This follows EK9's collection semantics: collections are always meaningful when created, even if empty. An empty dict is not the same as a missing dict.
emptyDict <- Dict() of (String, Integer) emptyDict? true (set) emptyDict is empty true (no entries)
See Q46 (How does the Dict type work?) for creation, DictEntry, adding/removing, getOrDefault, and basic iteration. See Q45 (How does the List type work?) for the sister collection type. See Q29 (How do unset variables work?) for tri-state semantics. See Q129 for safe access patterns with missing keys. See Q260 for Dict key type requirements and custom keys.
Use 'ek9 -h Dict' to see the full API.
Example
defines module qa.dict.operations defines program DictOperationsDemo() stdout <- Stdout() ages <- {"Alice": 30, "Bob": 25, "Charlie": 35} // === CONTAINS (KEY CHECK) === hasAlice <- ages contains "Alice" stdout.println(`Contains Alice: ${hasAlice}`) if "Bob" is in ages stdout.println("Found Bob") if "Zara" is not in ages stdout.println("Zara not found") // === KEYS AND VALUES ITERATORS === keyIter <- ages.keys() while keyIter? stdout.println(`Key: ${keyIter.next()}`) valIter <- ages.values() while valIter? stdout.println(`Value: ${valIter.next()}`) // === MERGING DICTS === d1 <- {"x": 1, "y": 2} d2 <- {"y": 99, "z": 3} // + creates a new merged dict merged <- d1 + d2 stdout.println(`Merged: ${merged}`) // :~: merge operator mutates left-hand side d1 :~: d2 stdout.println(`After merge: ${d1}`) // === COPY === copied <- Dict() of (String, Integer) copied :=: ages stdout.println(`Copied: ${copied}`) // === COMPARISON === c1 <- {"a": 1, "b": 2} c2 <- {"a": 1, "b": 2} c3 <- {"x": 9} require c1 == c2 require c1 <> c3 stdout.println(`c1 == c2: ${c1 == c2}`) stdout.println(`c1 <> c3: ${c1 <> c3}`) // === STRING AND JSON CONVERSION === asString <- $ages stdout.println(`As string: ${asString}`) stdout.println(`As JSON: ${$ ages}`) // === HASHCODE === hash <- #? ages stdout.println(`Hash: ${hash}`) // === EMPTY DICT IS SET === emptyDict <- Dict() of (String, Integer) require emptyDict? require emptyDict is empty stdout.println(`Empty dict isSet: ${emptyDict?}`) stdout.println(`Empty dict isEmpty: ${emptyDict is empty}`)
Common mistakes
E50060 — Dict has no get() method in EK9. Use the contains operator for key existence checks, or getOrDefault() for value retrieval with a fallback. See ek9 -h E50060 for details.
Incorrect:
hasAlice <- ages.get("Alice")
Correct:
hasAlice <- ages contains "Alice"
Other ways to ask this
- How do I get keys and values from an EK9 Dict?
- How do I check if a Dict contains a key in EK9?
- How do I merge, copy, or compare Dicts in EK9?
Coming from another language?
Java: HashMap .containsKey(), .keySet(), .values(), .putAll() for merge, no operator overloading. Python: 'in' operator, .keys(), .values(), dict union | (3.9+), == comparison. JavaScript: Object.keys(), Object.values(), spread for merge, no == comparison. Rust: .contains_key(), .keys(), .values(), .extend() for merge. Go: comma-ok idiom, no built-in merge or comparison. Kotlin: 'in' operator, .keys, .values, + for merge. EK9: 'contains'/'is in'/'is not in', .keys()/.values() iterators, + for new merged dict, :~: for in-place merge, :=: deep copy, == comparison, $$ for JSON.
Keywords: keys, copy, contains, hashcode, iterator, operations, first, dict, empty, set, start, values, json, intro, compare, merge, beginner