Learn
Lesson 6

Objects and maps

Group named values into objects, look things up by key with typed maps, and loop over both.

An object groups values under names, called keys. Write it in curly braces:

main.osl
object book = {
  title: "Dune",
  author: "Frank Herbert",
  year: 1965
}
log book.title
log book["year"]
log book
Click the code to edit it

Read a value with a dot, or with the key in square brackets when the key is in a variable or isn't a plain name. Objects print as JSON, with their keys in alphabetical order.

Changing objects#

Assign to a key to change it, or to add it if it isn't there yet. delete removes keys:

main.osl
object user = {name: "Ada"}
user.age = 36
user["role"] = "admin"
log user
user.delete("role")
log user
Click the code to edit it

Missing keys#

Reading a key that isn't there gives null, so pair it with ?? for a default:

main.osl
object settings = {theme: "dark"}
log settings.language
log settings.language ?? "en"
log settings.contains("theme")
Click the code to edit it

Nesting#

Values can be arrays or other objects, as deep as you like. This is the same shape as JSON, which is why objects are what you get when you parse JSON:

main.osl
object order = {
  id: 1042,
  customer: {name: "Grace", city: "Arlington"},
  items: ["keyboard", "mouse"]
}
log order.customer.name
log order.items[2]
order.items.append("cable")
log order.items.len
Click the code to edit it

Looping over objects#

for key, value in walks every entry. getKeys and getValues give you the keys or values as arrays. An object doesn't keep its keys in any particular order, so sort the keys when the order matters:

main.osl
object stock = {apples: 12, pears: 0, plums: 7}
for name in stock.getKeys().sort() (
  log name ++ ": " ++ stock[name]
)
log stock.getValues().sum()

int total = 0
for _, count in stock (
  total += count
)
log total
Click the code to edit it

Typed maps#

object holds values of any type, which is flexible but means the compiler can't check much. When every value has the same type, use a typed map. string[int] reads as "keys are strings, values are ints":

main.osl
string[int] wordCounts = {}
for word in "the cat and the hat".split(" ") (
  wordCounts[word] = (wordCounts[word] ?? 0) + 1
)
log wordCounts
log wordCounts["the"]
Click the code to edit it

The compiler now knows every value is an int, so wordCounts["the"] + 1 is checked and fast, and putting a string in by mistake is a compile error:

main.osl
string[int] ages = {}
ages["ada"] = "thirty-six"
Click the code to edit it

Building objects from variables#

When a key and a variable share a name, write it once. ... spreads one object into another, and later keys win:

main.osl
string name = "Ada"
int level = 3
object player = {name, level}
log player

object defaults = {sound: true, speed: 1}
object chosen = {...defaults, speed: 2}
log chosen
Click the code to edit it

++ merges two objects the same way: defaults ++ {speed: 2}.

Taking objects apart#

Destructuring pulls named keys into variables:

main.osl
object point = {x: 3, y: 4, label: "P"}
{x, y} = point
log x y
Click the code to edit it

Sharing and copying#

Like arrays, objects are shared when you assign them. .clone() makes an independent copy:

main.osl
object first = {count: 0}
object second = first
second.count = 1
log first.count

object third = first.clone()
third.count = 99
log first.count
Click the code to edit it
Quick check

object o = {a: 1}. What does log o.b print?

Your turn

Total stock

Print the total number of items in stock, and then the names of the items that have run out, in alphabetical order.

main.osl
Ctrl Enter runs
Expected output
42
["bread","milk"]
0 of 24 lessons done