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 | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
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 | ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
expression | ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
repetition | ||||||||||||
| ||||||||||||
| ||||||||||||
repetition | ||||||||||||
|
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 | ||||||||||||
| ||||||||||||
| ||||||||||||
repetition | ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
function | ||||||||||||
| ||||||||||||
expression | ||||||||||||
| ||||||||||||
| ||||||||||||
expression | ||||||||||||
| ||||||||||||
repetition | ||||||||||||
The Map.by variants create a map that uses the equality and hashing functions specified by key_comp for keys.
> m
{"x": 1, "y": 2}
> m["x"]
1
> Map(["x", 1], ["y", 2])
{"x": 1, "y": 2}
{"a": 4, "b": 4, "x": 1, "y": 2}
Map.by(===){"x": 1, "x": 2}
binding operator | ||||||||||||
| ||||||||||||
binding operator | ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
binding operator | ||||||||||||
| ||||||||||||
binding operator | ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
|
See Map and Set for more information.
The #%braces form is implicitly used when {…} is used in a binding position. See also Implicit Forms.
> y
2
> [a, z]
[1, 0]
> [more, ...]
["a", "c"]
binding operator | ||||||||||||
| ||||||||||||
binding operator | ||||||||||||
| ||||||||||||
binding operator | ||||||||||||
| ||||||||||||
binding operator | ||||||||||||
| ||||||||||||
| ||||||||||||
binding operator | ||||||||||||
| ||||||||||||
| ||||||||||||
binding operator | ||||||||||||
| ||||||||||||
| ||||||||||||
binding operator | ||||||||||||
| ||||||||||||
binding operator | ||||||||||||
| ||||||||||||
binding operator | ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
|
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.
> y
2
> [a, z]
[1, 0]
> rst
{"b": 2, "c": 3}
> [key, ...]
["c", "b"]
> [val, ...]
[3, 2]
"by object identity"
The Map.by reducer creates a map that uses the equality and hashing functions specified by key_comp.
expression | ||
| ||
| ||
function | ||
| ||
| ||
expression | ||
| ||
| ||
expression | ||
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 | ||
| ||
| ||
function | ||
| ||
| ||
expression | ||
| ||
| ||
expression | ||
value | |
| |
binding operator | |
| |
value | |
| |
binding operator | |
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.
{}
> 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"
method | |
|
> Map.length({"a": 1, "b": 2})
2
> Map.length({})
0
2
0
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: "d", 2: "b"}
{1: "d", 2: "b"}
Map.by(is_same_number_or_object){1: "d"},
)
{1: "c", 2: "b"}
> {1: "a", 2: "b"}
++ Map.by(is_same_number_or_object){1: "d"}
{1: "c", 2: "b"}
> Map.keys({"a": 1, "b": 2}, #true)
["a", "b"]
method | |
|
> Map.values({"a": 1, "b": 2})
[2, 1]
method | |||||
|
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
no value
> Map.remove({"a": 1, "b": 2}, "a")
{"b": 2}
> Map.remove({"a": 1, "b": 2}, "c")
{"a": 1, "b": 2}
> def m = MutableMap{"a": 1, "b": 2}
> m
MutableMap{"a": 3, "b": 2}
> m["a"] := 4
> m
MutableMap{"a": 4, "b": 2}
> def m = MutableMap{"a": 1, "b": 2}
> m
MutableMap{"a": 1, "b": 2}
> m
MutableMap{"b": 2}
method | |
| |
| |
method | |
|
> 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
method | |
> def m = MutableMap{"a": 1, "b": 2}
> m.copy()
MutableMap{"a": 1, "b": 2}
method | |
|
> def m = MutableMap{"a": 1, "b": 2}
> m.snapshot()
{"a": 1, "b": 2}
method | |
property | |
| |
annotation | |
| |
method | |
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.
> m[3]
Map.get: no value found for key
key: 3
#false
"a"
#true