Heroes / Examples / 10-maps

examples/gallery/10-maps.hero

Look up a map key and handle a missing entry explicitly.

A map associates keys with values. Looking up m[k] can find a value of type V or fail because the key is missing. Its return type is therefore V?, which makes the caller choose how to handle a missing entry.

Run it

$ heroes run examples/gallery/10-maps.hero

These files introduce the language one feature at a time. This page shows the program and not a result, because no test compares their output byte for byte yet.

The program

## Maps, and absence as a type
#
# `m[k]` does not return a `V`. It returns a `V?`, because the key might not
# be there — so the compiler makes you say what happens when it isn't. There
# is no null to forget to check.

# The four ways to read a `V?`, on one line each (§4.6).
function score_of(scores: {str: i64}, name: str) -> i64
    return scores[name].default(0)

function known(scores: {str: i64}, name: str) -> bool
    return !scores[name].is_err()

# `.is_err()` asks without extracting; the `match` extracts without aborting.
function report(scores: {str: i64}, name: str) -> str
    got = scores[name]

    if got.is_err()
        return name + " has no score"
    return name + " scored " + got.must().to_str()

# The general way, and the only one that names the error: `match` on `.ok`/`.err`.
function describe(scores: {str: i64}, name: str) -> str
    return match scores[name]
        .ok v  => v.to_str()
        .err e => e.code

# A map is built as a literal. There is no insert in the built-in inventory
# (§4.20) — `push` is for arrays — so this table is written, not accumulated.
function table() -> {str: i64}
    return {"ada": 10, "grace": 9, "alan": 8}

function total_of(scores: {str: i64}, names: [str]) -> i64
    sum: i64 @= 0

    for name in names
        sum @ sum + score_of(scores, name)

    return sum

test "a missing key is a type, not a crash"
    scores = table()
    assert score_of(scores, "ada") == 10
    assert score_of(scores, "nobody") == 0
    assert known(scores, "grace")
    assert known(scores, "nobody") == false
    assert scores.len() == 3

test "the four readings agree about presence and disagree about absence"
    scores = table()
    assert report(scores, "alan") == "alan scored 8"
    assert report(scores, "nobody") == "nobody has no score"
    assert describe(scores, "alan") == "8"

    # The spec names it now — `m[k]` returns a `V?` with code `missing_key` — so
    # this asserts it. It used to say the code was unspecified and assert only
    # that *something* came back, which was right on the day it was written and
    # became a comment contradicting the spec the moment the silence closed
    # (panel 034 R5: a document asserting something the compiler does not do).
    assert describe(scores, "nobody") == "missing_key"

function main()
    print(total_of(table(), ["ada", "grace", "nobody"]))
examples/gallery/10-maps.hero, 63 lines

fingerprint sha256 d29a9dd0d223 · 1 file · index.json

Next: 11-trees. All the examples. ← Previous: 09-holes

Run one yourself: the four commands. Learn the language, or read the full specification in one file.