4

Given the following code

defmodule Test do
  def run do
    p1 = {1, 2}
    m1 = %{a: p1}
    m2 = %{a: p1}
    IO.puts :erts_debug.same(m1.a, m2.a)
    m3 = %{b: p1}
    IO.puts :erts_debug.same(m1.a, m3.b)
  end
end

why does Test.run prints this

iex(1)> Test.run
true  <--- expected
false <--- not true ?!
:ok

Why are m1.a and m3.b not the same in-memory tuple?

mljrg
  • 4,430
  • 2
  • 36
  • 49

1 Answers1

3

modern era update: seems like it was fixed in ≈v1.7.

This is true for Elixir only; in Erlang the tuple is shared:

1> Tuple = {1, 2},
1> Key1 = 1,
1> Key2 = 2,
1> Map1 = #{1 => Tuple, 2 => Tuple},
1> erts_debug:same(maps:get(Key1,Map1), maps:get(Key2,Map1)).
true

2> Key3 = 3,
2> Map2 = #{3 => Tuple},
2> erts_debug:same(maps:get(Key1,Map1), maps:get(Key3,Map2)).
true

For Elixir, this is probably because of internal transpiler to erlang duplicates maps or like. I’d say this could be a great bug report to Elixir core.

In your example :erts_debug.same(m1.a, m2.a) prints true only due to :erts_debug.same(m1, m2) #⇒ true, e.g. maps themselves share the same memory.

Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
  • Could this have something to do with the fact that Elixir allows variables to be "mutable", i.e., unlike in Erlang where `A = {1, 2}` the variable `A` is bound to that tuple forever in the same scope, in Elixir it can be rebound to another value because internally it creates new variables? – Sasha Fonseca Dec 20 '18 at 16:13
  • @SashaFonseca Elixir does not allow variables to be mutable. It allows rebinding, and not, I don’t think it has anything to do with the above. As I said, I am positive it’s about not accurate syntax transpiling. – Aleksei Matiushkin Dec 20 '18 at 16:14
  • I understood what you meant variables as not being mutable, it's actually rebinding like you said. My usage of "mutable" was incorrect – Sasha Fonseca Dec 20 '18 at 17:36