On this page:
Map
Map.of
Map.later_  of
Readable  Map
Mutable  Map
Mutable  Map.now_  of
Mutable  Map.later_  of
Weak  Mutable  Map
Map.by
Mutable  Map.by
Weak  Mutable  Map.by
#%braces
#%braces
Map
Map
Map.by
Map.by
#%braces
Map
Readable  Map
Map.by
Map
Map.by
Mutable  Map
Mutable  Map.by
Weak  Mutable  Map
Weak  Mutable  Map.by
Map.empty
Map.empty
Readable  Map.empty
Readable  Map.empty
Map.length
Map.append
Map.keys
Map.values
Map.get
Map.remove
Mutable  Map.set
Mutable  Map.remove
Map.has_  key
Map.contains
Map.copy
Map.snapshot
Map.to_  sequence
Map.maybe
Map  Maybe
Map  Maybe.get
8.16.0.4

8.5 Maps🔗ℹ

A map associates a value with each of a set of keys. Immutable maps can be constructed using the syntax {key_expr: val_expr, ...}, which creates a map from the values of the key_exprs to the corresponding values of the val_exprs. Note that using , in place of : creates a set with separate values, instead of a key–value mapping. More precisely, a use of curly braces with no preceding expression is parsed as an implicit use of the #%braces form.

A map is indexable using [] after a map expression with an expression for the key within []. Mutable maps can be updated with a combination of [] and assignment operators such as := (but use ++ to functionally update an immutable map). These uses of square brackets are implemented by #%index. A map also supports membership tests via in, which checks for keys (not values) the same as Map.has_key. A map can be used as sequence, in which case it supplies a key and its associated value (as two result values) in an unspecified order.

annotation

Map

 

annotation

Map.of(key_annot, val_annot)

 

annotation

Map.later_of(key_annot, val_annot)

 

annotation

ReadableMap

 

annotation

MutableMap

 

annotation

MutableMap.now_of(key_annot, val_annot)

 

annotation

MutableMap.later_of(key_annot, val_annot)

 

annotation

WeakMutableMap

 

annotation

Map.by(key_comp)

 

annotation

Map.by(key_comp).of(key_annot, val_annot)

 

annotation

MutableMap.by(key_comp)

 

annotation

WeakMutableMap.by(key_comp)

The Map annotation matches any immutable map. ReadableMap matches both mutable and immutable maps, while MutableMap matches mutable maps (created with, for example, the MutableMap constructor). WeakMutableMap matches weak mutable maps (created with, for example, the WeakMutableMap constructor).

The of and now_of annotation variants match a map whose keys satisfy key_annot and whose values satisfy val_annot, where satisfaction of the annotation is confirmed by immediately checking all keys and values. No future obligation is attached to a map satisfying the annotation, so in the case of MutableMap.now_of, no static information is associated with value access using [].

The later_of annotation variants create a converter annotation given annotations for keys and values; satisfaction of those annotations is confirmed only on demand, both for keys and values that are extracted from the map and for keys and values added or appended to the map. For Map.later_of, the key and value annotations must be predicate annotations. Since a value annotation is checked on every access, its static information is associated with access using [].

The Map.by, MutableMap.by, and WeakMutableMap.by annotation variants match only maps that use the hash and equality functions specified by key_comp.

Static information associated by Map, etc., makes an expression acceptable as a sequence to for in static mode.

expression

#%braces {key_val_or_splice, ...}

 

key_val_or_splice

 = 

key_expr: val_body; ...

 | 

key_repet: val_repet , ellipses

 | 

& map_expr

 

expression

#%braces {expr_or_splice, ...}

 

expr_or_splice

 = 

elem_expr

 | 

elem_repet , ellipses

 | 

& set_expr

 

ellipses

 = 

ellipsis

 | 

ellipses , ellipsis

 

ellipsis

 = 

...

 

repetition

#%braces {key_repet_or_splice, ...}

 

repetition

#%braces {repet_or_splice, ...}

Constructs either an immutable map or immutable set, depending on whether key_expr and val_expr are provided or elem_expr is provided. If no elements are provided directly, the result is a map (not a set). Map/set constructions can also serve as repetitions, where key_repet_or_splice and repet_or_splice are like key_val_or_splice and expr_or_splice, but with repetitions in place of expressions and body sequences.

When ... is used among the content with two repetitions (for a map) or one repetition (for a set), the paired key and value elements (for a map) or value elements (for a set) are included in the result map or set. When & map_expr or & set_expr appears among the content, the immutable map or immutable set produced by map_expr or set_expr is included in the result map or set. This inclusion respects the map configuration specified by the construction.

Mappings or elements are added to the result map or set left-to-right, which means that a later key_expr or elem_expr may replace one earlier in the sequence. This ordering applies to mappings or elements spliced via ... and &, too.

The #%braces form is implicitly used when {} is used in an expression or repetition position. See also Implicit Forms.

> {1, 2, 3}

{1, 2, 3}

> {"a": 1, "b": 2}

{"a": 1, "b": 2}

> #%braces {1, 2, 3}

{1, 2, 3}

> #%braces {"a": 1, "b": 2}

{"a": 1, "b": 2}

> {1, 2, & {3, 4}}

{1, 2, 3, 4}

> {"a": 1, "b": 2, & {"c": 3, "d": 4}}

{"a": 1, "b": 2, "c": 3, "d": 4}

expression

Map{key_val_or_splice, ...}

 

repetition

Map{key_repet_or_splice, ...}

 

key_val_or_splice

 = 

key_expr: val_expr

 | 

key_repet: val_repet , ellipsis

 | 

& map_expr

 

ellipsis

 = 

...

 

function

fun Map([key :: Any, val :: Any] :: Listable.to_list, ...)

  :: Map

 

expression

Map.by(key_comp){key_val_or_splice, ...}

 

expression

Map.by(key_comp)

 

repetition

Map.by(key_comp){key_repet_or_splice, ...}

Constructs an immutable map containing given keys mapped to the given values, equivalent to using {key_val_or_splice, ...} for the {} form, or {key: val, ...} for the function form. The {} form works as a repetition, where key_repet_or_splice is like key_val_or_splice with repetitions in place of expressions.

The Map.by variants create a map that uses the equality and hashing functions specified by key_comp for keys.

> def m = Map{"x": 1, "y": 2}

> m

{"x": 1, "y": 2}

> m["x"]

1

> Map(["x", 1], ["y", 2])

{"x": 1, "y": 2}

> Map{"a": 4, "b": 4, & m}

{"a": 4, "b": 4, "x": 1, "y": 2}

> Map.by(===){"x" +& "": 1, "" +& "x": 2}

Map.by(===){"x": 1, "x": 2}

binding operator

#%braces {key_val, ...}

 

binding operator

#%braces {key_val, ..., map_rest}

 

key_val

 = 

key_expr: val_bind = default_expr

 | 

key_expr: val_bind: default_body; ...

 | 

key_expr: val_bind

 

map_rest

 = 

& map_bind

 | 

rest_key_bind: rest_val_bind , ellipsis

 

binding operator

#%braces {expr, ...}

 

binding operator

#%braces {expr, ..., set_rest}

 

set_rest

 = 

& set_bind

 | 

rest_bind , ellipsis

 

ellipsis

 = 

...

Matches either an immutable map or immutable set, depending on whether key_expr and val_bind are provided or expr is provided. If no key_expr or expr are provided, the binding matches a map (not a set).

See Map and Set for more information.

The #%braces form is implicitly used when {} is used in a binding position. See also Implicit Forms.

> def {"x": x, "y": y} = Map{"x": 1, "y": 2}

> y

2

> def Map{"a": a, "z": z = 0} = {"a": 1, "b": 2, "c": 3}

> [a, z]

[1, 0]

> def {"b", more, ...} = Set{"a", "b", "c"}

> [more, ...]

["a", "c"]

binding operator

Map{key_val, ...}

 

binding operator

Map{key_val, ..., rest}

 

binding operator

Map([key_expr, val_bind], ...)

 

binding operator

ReadableMap{key_val, ...}

 

binding operator

ReadableMap{key_val, ..., rest}

 

binding operator

ReadableMap([key_expr, val_bind], ...)

 

binding operator

Map.by(key_comp){key_val, ...}

 

binding operator

Map.by(key_comp){key_val, ..., rest}

 

binding operator

Map.by(key_comp)([key_expr, val_bind], ...)

 

key_val

 = 

key_expr: val_bind = default_expr

 | 

key_expr: val_bind: default_body; ...

 | 

key_expr: val_bind

 

rest

 = 

& map_bind

 | 

rest_key_bind: rest_val_bind , ellipsis

 

ellipsis

 = 

...

Matches a map of the keys computed by key_expr to values that match the corresponding val_binds. The matched map may have additional keys and values. If default_expr or default_body is supplied, the key is optional, and the default_expr or default_body is used to produce a “default” value to further match in case the key is missing in the matched map. If & map_bind is supplied, the rest of the map excluding the given key_exprs must match the map_bind. Static information associated by Map is propagated to map_bind. If rest_key_bind: rest_val_bind followed by ... is supplied, the rest of the map excluding the given key_exprs must have individual keys that match rest_key_bind and values that match rest_val_bind, and identifiers in rest_key_bind and rest_val_bind are bound as repetitions. Values matching rest_key_bind and rest_val_bind are extracted eagerly and preserved in internal lists to implement the repetitions.

The Map binding forms match only immutable maps, while ReadableMap forms match both immutable and mutable maps. For ReadableMap, the & map_bind will match a snapshot (in the sense of Map.snapshot) of the rest of the map. The Map.by binding forms match only immutable maps constructed using key_comp.

> def Map{"x": x, "y": y} = {"x": 1, "y": 2}

> y

2

> def Map{"a": a, "z": z = 0} = {"a": 1, "b": 2, "c": 3}

> [a, z]

[1, 0]

> def Map{"a": _, & rst} = {"a": 1, "b": 2, "c": 3}

> rst

{"b": 2, "c": 3}

> def Map{"a": _, key: val, ...} = {"a": 1, "b": 2, "c": 3}

> [key, ...]

["c", "b"]

> [val, ...]

[3, 2]

> match Map.by(===){}

  | Map.by(==){}: "by equal"

  | Map.by(===){}: "by object identity"

"by object identity"

reducer

Map

 

reducer

Map.by(key_comp)

A reducer used with for, expects two results from a for body, and accumulates them into a map using the first result as a key and the second result as a value.

The Map.by reducer creates a map that uses the equality and hashing functions specified by key_comp.

expression

MutableMap{key_expr: val_expr, ...}

 

function

fun MutableMap([key :: Any, val :: Any] :: Listable.to_list, ...)

  :: MutableMap

 

expression

MutableMap.by(key_comp){key_expr: val_expr, ...}

 

expression

MutableMap.by(key_comp)

Similar to Map as a constructor, but creates a mutable map that can be updated using an assignment operator like :=.

Note that ... and & are not supported for constructing mutable maps, only immutable maps.

> def m = MutableMap{"x": 1, "y": 2}

> m

MutableMap{"x": 1, "y": 2}

> m["x"]

1

> m["x"] := 0

> m

MutableMap{"x": 0, "y": 2}

expression

WeakMutableMap{key_expr: val_expr, ...}

 

function

fun WeakMutableMap([key :: Any, val :: Any] :: Listable.to_list, ...)

  :: WeakMutableMap

 

expression

WeakMutableMap.by(key_comp){key_expr: val_expr, ...}

 

expression

WeakMutableMap.by(key_comp)

Like MutableMap, but creates a map where a key is removed from the map by a garbage collection when the key is reachable only by enumerating the map’s keys. A key is not considered reachable merely because it is reachable through the value mapped from the key.

value

def Map.empty :: Map = {}

 

binding operator

Map.empty

 

value

def ReadableMap.empty :: ReadableMap = {}

 

binding operator

ReadableMap.empty

An empty map. The Map.empty binding form differs from from {} or Map{}, because Map.empty matches only an empty immutable map, while {} or Map{} matches any immutable map.

The ReadableMap.empty binding form matches an empty map whether it is mutable or immutable.

Corresponding to the binding forms, Map.empty and ReadableMap.empty are bound to {} with appropriate static information.

> Map.empty

{}

> match {}

  | Map.empty: "empty map"

  | _: #false

"empty map"

> match {"x": 1, "y": 2}

  | Map.empty: "empty map"

  | _: #false

#false

> match {"x": 1, "y": 2}

  | {}: "curly braces allow extra"

  | _: #false

"curly braces allow extra"

> match {"x": 1, "y": 2}

  | Map(): "Map binding allows extra"

  | _: #false

"Map binding allows extra"

> match MutableMap{}

  | Map.empty: "empty immutable map"

  | _: #false

#false

> match MutableMap{}

  | ReadableMap.empty: "empty map for now"

  | _: #false

"empty map for now"

Returns the number of key–value mappings in mp.

> Map.length({"a": 1, "b": 2})

2

> Map.length({})

0

> {"a": 1, "b": 2}.length()

2

> {}.length()

0

method

method (mp :: Map).append(another_mp :: Map, ...) :: Map

Functionally appends mp and another_mps, like the ++ operator (but without the special optimization for adding a single key). When a key has a value in multiple given maps, the rightmost value is used.

Even when another_mp uses a different map configuration than mp, the configuration of mp is preserved for the result. Conceptually, in the binary case, each key–value mapping from the right map is added to the left map.

> {1: "a", 2: "b"}.append({1: "c"}, {1: "d"})

{1: "d", 2: "b"}

> {1: "a", 2: "b"} ++ {1: "c"} ++ {1: "d"}

{1: "d", 2: "b"}

> {1: "a", 2: "b"}.append(

    Map.by(is_same_number_or_object){1: "d"},

    Map.by(is_now){1: "c"},

  )

{1: "c", 2: "b"}

> {1: "a", 2: "b"}

    ++ Map.by(is_same_number_or_object){1: "d"}

    ++ Map.by(is_now){1: "c"}

{1: "c", 2: "b"}

method

method Map.keys(mp :: ReadableMap,

                try_sort :: Any = #false)

  :: List

Returns the keys of mp in a list. If try_sort is true, then the elements are sorted to the degree that a built-in comparison can sort them.

> Map.keys({"a": 1, "b": 2}, #true)

["a", "b"]

Returns the values of mp in a list.

> Map.values({"a": 1, "b": 2})

[2, 1]

method

method Map.get(mp :: ReadableMap,

               key :: Any,

               default :: Any:

                 fun (): throw Exn.Fail.Contract(....))

  :: Any

Equivalent mp[key] (with the default implicit #%index form) when default is not provided, otherwise default is used when mp does not contain a mapping for key. In that case, if default is a function, then the function is called with zero arguments to get a result, otherwise default is returned as the result.

See also Map.maybe.

> Map.get({"a": 1, "b": 2}, "a")

1

> {"a": 1, "b": 2}["a"]

1

> Map.get({"a": 1, "b": 2}, "c", #inf)

#inf

> Map.get({"a": 1, "b": 2}, "c", fun (): error("no value"))

no value

method

method (mp :: Map).remove(key :: Any) :: Map

Returns a map like mp, but without a mapping for key is mp has one.

> Map.remove({"a": 1, "b": 2}, "a")

{"b": 2}

> Map.remove({"a": 1, "b": 2}, "c")

{"a": 1, "b": 2}

method

method (mp :: MutableMap).set(key :: Any, val :: Any)

  :: Void

Equivalent to mp[key] := val (with the default implicit #%index form). Changes mp to map key to val.

> def m = MutableMap{"a": 1, "b": 2}

> m.set("a", 3)

> m

MutableMap{"a": 3, "b": 2}

> m["a"] := 4

> m

MutableMap{"a": 4, "b": 2}

method

method (mp :: MutableMap).remove(key :: Any) :: Void

Changes mp to remove a mapping for key, if any.

> def m = MutableMap{"a": 1, "b": 2}

> m.remove("c")

> m

MutableMap{"a": 1, "b": 2}

> m.remove("a")

> m

MutableMap{"b": 2}

method

method Map.has_key(mp :: ReadableMap, key :: Any) :: Boolean

 

method

method Map.contains(mp :: ReadableMap, key :: Any) :: Boolean

Returns #true if key is mapped to a value in mp, #false otherwise. The Map.contains method is a synonym for Map.has_key and reflects how a map supports in.

> Map.has_key({"a": 1, "b": 2}, "a")

#true

> Map.has_key({"a": 1, "b": 2}, "c")

#false

> Map.contains({"a": 1, "b": 2}, "a")

#true

> "a" in {"a": 1, "b": 2}

#true

Creates a mutable map whose initial content matches mp.

> def m = {"a": 1, "b": 2}

> m.copy()

MutableMap{"a": 1, "b": 2}

> def m = MutableMap{"a": 1, "b": 2}

> m.copy()

MutableMap{"a": 1, "b": 2}

Returns an immutable map whose content matches mp. If mp is immutable, then it is the result.

> def m = {"a": 1, "b": 2}

> m.snapshot()

{"a": 1, "b": 2}

> m.snapshot() === m

#true

> def m = MutableMap{"a": 1, "b": 2}

> m.snapshot()

{"a": 1, "b": 2}

Implements Sequenceable by returning a sequence of mp’s keys and values (as two result values) in an unspecified order.

property

property Map.maybe(mp :: ReadableMap) :: MapMaybe

 

annotation

MapMaybe

 

method

method (mm :: MapMaybe).get(key :: Any) :: Any

The Map.maybe property produces a MapMaybe value, and the MapMaybe.get operation on that result is the same as using Map.get on the original map with #false as the default.

A MapMaybe object is indexable using [] to invoke the MapMaybe.get operation. When the Map.maybe property is accessed as mp.maybe, and when the map expression mp has static information for its values, then the mp.maybe expression has static information as the maybe of the map’s values for its values.

The combination mp.maybe[key] (with the default implicit #%index form) is optimized in that no intermediate MapMaybe value is constructed.

> def m = { 1: "a", 2: "b" }

> m[3]

Map.get: no value found for key

  key: 3

> m.maybe[3]

#false

> m.maybe[1]

"a"

> m.maybe is_a MapMaybe

#true