Map
In Goblin, a map is a collection of key-value pairs. Keys are unique. Values can be anything. Maps are unordered — keys are stored alphabetically internally.
Creating a Map
person | { name: "Daniel" age: 44 active: true }
person | { name: "Daniel" age: 44 active: true }
Keys are bare identifiers. Values are any Goblin expression.
Single-line form using commas:
person | { name: "Daniel", age: 44 }
person | { name: "Daniel", age: 44 }
Map Lookup
Map lookup uses braces:
person{"name"} /// -> "Daniel" person{"age"} /// -> 44
person{"name"} /// -> "Daniel" person{"age"} /// -> 44
This is intentional. Arrays use brackets for positional lookup. Maps use braces for keyed lookup. The syntax tells you what kind of operation you are reading.
routes[0] /// positional — this is an array person{"name"} /// keyed — this is a map
routes[0] /// positional — this is an array person{"name"} /// keyed — this is a map
If you use braces on an array, Goblin errors:
routes{"name"} /// error: used {} on an array — arrays use positional lookup with []
routes{"name"} /// error: used {} on an array — arrays use positional lookup with []
Key That Does Not Exist
If the key is missing, Goblin errors:
person{"email"} /// error: no-such-key: missing key 'email'
person{"email"} /// error: no-such-key: missing key 'email'
Check first with :has before reading an uncertain key:
if :has(person, "email") => say person{"email"}
if :has(person, "email") => say person{"email"}
Updating an Entry
Use :update! with brace lookup:
:update!(person{"age"}, 45)
:update!(person{"age"}, 45)
Or use :update_at!:
:update_at!(person, "age", 45)
:update_at!(person, "age", 45)
:update_at! errors if the key does not already exist.
Adding an Entry
Use :put_at!:
:put_at!(person, "email", "dan@example.com")
:put_at!(person, "email", "dan@example.com")
:put_at! inserts the key if it does not exist, or overwrites it if it does.
Removing an Entry
Use :delete_at!:
:delete_at!(person, "email")
:delete_at!(person, "email")
Remove all entries matching a predicate on values:
:delete_where!(person, "is_nil")
:delete_where!(person, "is_nil")
Reading a Value by Key
:grab_at returns a value by key without modifying the map:
val | :grab_at(person, "age") /// -> 44, person unchanged
val | :grab_at(person, "age") /// -> 44, person unchanged
Remove and Return a Value
:reap_at! removes a key and returns its value:
name | :reap_at!(person, "name") /// name -> "Daniel" /// person no longer has "name" key
name | :reap_at!(person, "name") /// name -> "Daniel" /// person no longer has "name" key
Checking for a Key
:has(person, "name") /// -> true :has(person, "email") /// -> false
:has(person, "name") /// -> true :has(person, "email") /// -> false
Counting Entries
:count(person) /// -> 2
:count(person) /// -> 2
Iterating
Keys only
k_list | :keys(person) /// -> [age, name]
k_list | :keys(person) /// -> [age, name]
Values only
v_list | :values(person) /// -> [44, Daniel]
v_list | :values(person) /// -> [44, Daniel]
Key-value pairs
:items returns an array of pairs:
:items(person) /// -> [(age, 44), (name, Daniel)]
:items(person) /// -> [(age, 44), (name, Daniel)]
To walk keys and values together, use :keys with lookup:
for key in :keys(person) val | person{key} say key say val xx
for key in :keys(person) val | person{key} say key say val xx
Type Check
:valtype(person) /// -> "map"
:valtype(person) /// -> "map"