Different closure between Erlang and Elixir

Elixir allows to rebind the variables, so this is perfectly possible to do:

a = 1
a = 2

Which will then be translated to Erlang as a something like:

A@1 = 1
A@2 = 2

To have the same behaviour as in Erlang, you need to use pin operator (^):

a = 1
^a = 2 # will fail with no match

So in your case you need to write it as:

receive do
  {:DOWN, ^ref, :process, ^pid, why} -> why
end

To “pin down” the variables to their current binding instead of creating new ones.