[erlang-questions] Status of map pair support in dialyzer

Magnus Lång margnus1@REDACTED
Mon Apr 11 14:23:20 CEST 2016

On 2016-04-11 13:25, José Valim wrote:
> That's excellent news Kostis!
> I have only one question/reservation:
>     Another problem is related to the meaning of #{}. One would expect
>     that this notation means "the empty map," but instead it means
>     "any map".
> #{} in pattern matching also means "any map", so it may be confusing 
> to have #{} in specs to mean the empty map, specially because both 
> usages are often close to each other. For example:
>     -spec increment(term(), #{}) -> #{}
>     increment(Key, #{} = Map) ->
>       Map#{Key := maps:get(Key, Map) + 1}.
> I also understand that [] and {} in typespecs implies emptiness and 
> making #{} mean "the empty map" would make the typespecs more consistent.
Actually, that is not the reason I wanted to make this change. Rather, 
it is inconsistent with the #{PairList} syntax. Consider the type 
#{x=>_, y=>_}. This type may only contain the keys x and y. So, the 
value #{x=>1, y=>2, z=>3} does not belong to this type.
Now consider what happens when we change the type to #{x=>_}; the type 
is made more restrictive. The key y is no longer allowed. But if we 
repeat this process and change it to #{}, suddenly we have not made the 
type more restrictive; we made it more allowing!

In fact, I have seen several people (myself included!) be fooled by the 
#{} base case into believing that the #{x=>_, y=>_}, means the set of 
values that match the pattern #{x=>_, y=>_}, which is not the case 
(written with the new syntax, that type would be #{x:=_, y:=_, ...}).

So, I saw an opportunity to make the syntax self-consistent and more 
intuitive before it would become harder to change. Either by changing 
the semantics of everything but #{} in order to be consistent with 
pattern matches, or by just changing #{} to be consistent with the rest.

Considering that the former would have broken the ability to write 
associative-array-maps as #{Key => Value} (or required even more special 
cases), the choice was clear.

> That said, maybe it would be better to not allow #{} altogether 
> (deprecating it now and removing it later) and introduce an 
> empty_map() construct? The empty_map() type is slightly more verbose 
> but I don't expect it to be used frequently and, as such, the more 
> explicit name is worth it. And if I understand the proposal correctly, 
> both map() and #{_ => _} can still be used to represent any map, while 
> #{_ := _} represents a non-empty map, so it feels all of our bases are 
> covered.
> Thank you,
Although I am not against introducing an empty_map() alias, I don't 
think disallowing #{} would solve the problem. Indeed, your example can 
be trivially altered to commit the same mistake without using the #{} type;

    -spec increment(term(), #{count := C}) -> #{count := C}.

    increment(Key, #{count := C} = Map) when C >= 0 ->
       Map#{Key := maps:get(Key, Map) + 1}.

If anything, I think the #{} case is the clearest example of type =/= 
pattern, and removing it would just obscure the problem.

Thanks for your feedback
// Magnus Lång

> *José Valim*
> www.plataformatec.com.br <http://www.plataformatec.com.br/>
> Skype: jv.ptec
> Founder and Director of R&D
> On Mon, Apr 11, 2016 at 12:45 PM, Kostis Sagonas <kostis@REDACTED 
> <mailto:kostis@REDACTED>> wrote:
>     On 03/04/2016 11:59 AM, Björn-Egil Dahlberg XB wrote:
>         I did the initial work for maps in Dialyzer but that
>         application is not
>         really part of my work area. If you want to contribute to
>         Dialyzer you
>         should probably talk to Hans Bolinder, Kostis Sagonas and/or
>         Stavros
>         Aronis. Hans talked about increasing Dialyzers knowledge about map
>         associations the other day but I don't think it is on his
>         agenda at the
>         moment.
>         I don't think it will be supported in 19.0 either though I
>         have no clue
>         if Kostis or Stavros, or anyone else for that matter, is
>         working on it.
>     Hijacking this thread to announce a proposal for a change in the
>     type syntax related to maps.
>     The relevant document is here:
>     https://gist.github.com/kostis/eaf4a06e643cf49314ba
>     We would appreciate feedback from the community at this point.
>     The intention is for this change to be part of Erlang/OTP 19.0.
>     Kostis
>     PS. Most of the credit for this change goes to Magnus Lång.
>     PS2. For those that would like to experiment with the new type
>     syntax and use the new version of dialyzer, or just fancy reading
>     code diffs, there is also a related pull request that implements
>     all these:
>     https://github.com/erlang/otp/pull/1014
>     _______________________________________________
>     erlang-questions mailing list
>     erlang-questions@REDACTED <mailto:erlang-questions@REDACTED>
>     http://erlang.org/mailman/listinfo/erlang-questions
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20160411/a6e6c9dd/attachment.htm>

More information about the erlang-questions mailing list