<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> <header> <copyright> <year>2014</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> The contents of this file are subject to the Erlang Public License, Version 1.1, (the "License"); you may not use this file except in compliance with the License. You should have received a copy of the Erlang Public License along with this software. If not, it can be retrieved online at http://www.erlang.org/. Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. </legalnotice> <title>Maps</title> <prepared></prepared> <docno></docno> <date></date> <rev></rev> <file>maps.xml</file> </header> <note> <p>Maps are considered experimental during OTP 17 and may be subject to change.</p> <p>The documentation below describes it being possible to use arbitrary expressions or variables as keys, this is <em>NOT</em> implemented in the current version of Erlang/OTP.</p> <p>Exceptions returns <c>badarg</c> instead of <c>badmap</c>, this will change in the future releases.</p> </note> <section> <title>Creating Maps</title> <p> Constructing a new map is done by letting an expression <c>K</c> be associated with another expression <c>V</c>: </p> <code>#{ K => V }</code> <p> New maps may include multiple associations at construction by listing every association: </p> <code>#{ K1 => V1, .., Kn => Vn }</code> <p> An empty map is constructed by not associating any terms with each other: </p> <code>#{}</code> <p> All keys and values in the map are terms. Any expression is first evaluated and then the resulting terms are used as <em>key</em> and <em>value</em> respectively. </p> <p> Keys and values are separated by the <c>=></c> arrow and associations are separated by <c>,</c>. </p> <p> Examples: </p> <code> M0 = #{}, % empty map M1 = #{a => <<"hello">>}, % single association with literals M2 = #{1 => 2, b => b}, % multiple associations with literals M3 = #{k => {A,B}}, % single association with variables M4 = #{{"w", 1} => f()}. % compound key associated with an evaluated expression</code> <p> where, <c>A</c> and <c>B</c> are any expressions and <c>M0</c> through <c>M4</c> are the resulting map terms. </p> <p> If two matching keys are declared, the latter key will take precedence. </p> <p> Example: </p> <pre> 1> <input>#{1 => a, 1 => b}.</input> #{1 => b } 2> <input>#{1.0 => a, 1 => b}.</input> #{1 => b, 1.0 => a} </pre> <p> The order in which the expressions constructing the keys and their associated values are evaluated is not defined. The syntactic order of the key-value pairs in the construction is of no relevance, except in the above mentioned case of two matching keys. </p> </section> <section> <title>Updating Maps</title> <p> Updating a map has similar syntax as constructing it. </p> <p> An expression defining the map to be updated is put in front of the expression defining the keys to be updated and their respective values. </p> <code>M#{ K => V }</code> <p> where <c>M</c> is a term of type map and <c>K</c> and <c>V</c> are any expression. </p> <p> If key <c>K</c> does not match any existing key in the map, a new association will be created from key <c>K</c> to value <c>V</c>. If key <c>K</c> matches an existing key in map <c>M</c> its associated value will be replaced by the new value <c>V</c>. In both cases the evaluated map expression will return a new map. </p> <p> If <c>M</c> is not of type map an exception of type <c>badmap</c> is thrown. </p> <p> To only update an existing value, the following syntax is used, </p> <code>M#{ K := V } </code> <p> where <c>M</c> is an term of type map, <c>V</c> is an expression and <c>K</c> is an expression which evaluates to an existing key in <c>M</c>. </p> <p> If key <c>K</c> does not match any existing keys in map <c>M</c> an exception of type <c>badarg</c> will be triggered at runtime. If a matching key <c>K</c> is present in map <c>M</c> its associated value will be replaced by the new value <c>V</c> and the evaluated map expression returns a new map. </p> <p> If <c>M</c> is not of type map an exception of type <c>badmap</c> is thrown. </p> <p> Examples: </p> <code> M0 = #{}, M1 = M0#{a => 0}, M2 = M1#{a => 1, b => 2}, M3 = M2#{"function" => fun() -> f() end}, M4 = M3#{a := 2, b := 3}. % 'a' and 'b' was added in `M1` and `M2`.</code> <p> where <c>M0</c> is any map. It follows that <c>M1 .. M4</c> are maps as well. </p> <p> More Examples: </p> <pre> 1> <input>M = #{1 => a}.</input> #{1 => a } 2> <input>M#{1.0 => b}.</input> #{1 => a, 1.0 => b}. 3> <input>M#{1 := b}.</input> #{1 => b} 4> <input>M#{1.0 := b}.</input> ** exception error: bad argument </pre> <p> As in construction, the order in which the key and value expressions are evaluated is not defined. The syntactic order of the key-value pairs in the update is of no relevance, except in the case where two keys match, in which case the latter value is used. </p> </section> <section> <title>Maps in Patterns</title> <p> Matching of key-value associations from maps is done in the following way: </p> <code>#{ K := V } = M</code> <p> where <c>M</c> is any map. The key <c>K</c> has to be an expression with bound variables or a literals, and <c>V</c> can be any pattern with either bound or unbound variables. </p> <p> If the variable <c>V</c> is unbound, it will be bound to the value associated with the key <c>K</c>, which has to exist in the map <c>M</c>. If the variable <c>V</c> is bound, it has to match the value associated with <c>K</c> in <c>M</c>. </p> <p> Example: </p> <code> 1> <input>M = #{"tuple" => {1,2}}.</input> #{"tuple" => {1,2}} 2> <input>#{"tuple" := {1,B}} = M.</input> #{"tuple" => {1,2}} 3> <input>B.</input> 2.</code> <p> This will bind variable <c>B</c> to integer <c>2</c>. </p> <p> Similarly, multiple values from the map may be matched: </p> <code>#{ K1 := V1, .., Kn := Vn } = M</code> <p> where keys <c>K1 .. Kn</c> are any expressions with literals or bound variables. If all keys exist in map <c>M</c> all variables in <c>V1 .. Vn</c> will be matched to the associated values of their respective keys. </p> <p> If the matching conditions are not met, the match will fail, either with </p> <list> <item> a <c>badmatch</c> exception, if used in the context of the matching operator as in the example, </item> <item> or resulting in the next clause being tested in function heads and case expressions. </item> </list> <p> Matching in maps only allows for <c>:=</c> as delimiters of associations. The order in which keys are declared in matching has no relevance. </p> <p> Duplicate keys are allowed in matching and will match each pattern associated to the keys. </p> <code>#{ K := V1, K := V2 } = M</code> <p> Matching an expression against an empty map literal will match its type but no variables will be bound: </p> <code>#{} = Expr</code> <p> This expression will match if the expression <c>Expr</c> is of type map, otherwise it will fail with an exception <c>badmatch</c>. </p> <section> <title>Matching syntax: Example with literals in function heads</title> <p> Matching of literals as keys are allowed in function heads. </p> <code> %% only start if not_started handle_call(start, From, #{ state := not_started } = S) -> ... {reply, ok, S#{ state := start }}; %% only change if started handle_call(change, From, #{ state := start } = S) -> ... {reply, ok, S#{ state := changed }};</code> </section> </section> <section> <title>Maps in Guards</title> <p> Maps are allowed in guards as long as all sub-expressions are valid guard expressions. </p> <p> Two guard BIFs handles maps: </p> <list> <item> <seealso marker="erts:erlang#is_map/1">is_map/1</seealso> </item> <item> <seealso marker="erts:erlang#map_size/1">map_size/1</seealso> </item> </list> </section> </chapter>