`:erlang."=:="/2` does not seem to check map sizes before performing the thoroughful comparison

This question is based on https://stackoverflow.com/questions/60095214/which-way-to-compare-maps-in-elixir


Assume a comparison of two huge maps. Erlang documentation explicitly states

Maps are ordered by size, two maps with the same size are compared by keys in ascending term order and then by values in key order. In maps key order integers types are considered less than floats types.

The simple check shows it’s not exactly the case

[m1, m2] = Enum.map([1, 2], fn i -> Map.new(Enum.map(i..1_000_000, &{&1, &1})) end)

Enum.map([true, false], &:timer.tc(fn ->
  (&1 or map_size(m1) == map_size(m2)) && :erlang."=:="(m1, m2)
end))
#⇒ [{14941, false}, {20, false}]

# BUT
Enum.map([true, false], &:timer.tc(fn ->
  (&1 or map_size(m1) == map_size(m2)) && :erlang."=="(m1, m2)
end)) 
#⇒ [{35, false}, {33, false}]

Note the enormously huge number in the first case when map_size/1 is not called. The above makes me think that :erlang."=:="/2 does not check sizes upfront.

Unfortunately, I was unable to grep the NIF where the implementation of :erlang."=:="/2 is defined (where otp/erts/preloaded/src/erlang.erl:4176 stub points to.)

So, my question would be: could please anyone more competent in OTP source point me to the implementation and should not we fix Map.equal?/2 in Elixir meanwhile to check for sizes before delegating to :erlang."=:="/2?

/cc @josevalim

1 Like

For me it seems like omission in the BEAM, so I think it should be fixed upstream to make =:= check for sizes as well.

Sure thing. That is why I asked for the link to NIF in the first place.

These are BIFs defined in erts/

For erlang:'=:='/2 - erts/emulator/beam/utils.c:2707
For erlang:'=='/2 - erts/emulator/beam/erl_utils.h:128

1 Like

Seems like this optimization is not done for large maps for some reason.

1 Like

I honestly cannot see any reason for avoiding it explicitly for big maps. /cc @rvirding

It is probably just an oversight/missed optimization in the implementation.

4 Likes

Should we file a bug report? Or it already planned to be handled? :slight_smile:

Fixed in this pull request: https://github.com/erlang/otp/pull/2526

9 Likes