Why elixir debugger is calling built-in function instead of mine if they have same name

88 views Asked by At

Here is a simple module with 2 breakpoints in functions which are calling another functions with names exactly the same as built-in ones: get/1 and put/2

defmodule Test do
  def call_put() do
    require IEx; IEx.pry
    put("k", "v")
  end
  def call_get() do
    require IEx; IEx.pry
    get("k")
  end

  def put(_k, _v)do
    IO.puts("Doing put")
  end
  def get(_k) do
    IO.puts("Doing get")
  end
end

Executing it in a shell:

iex(1)> Test.call_get
Break reached: Test.call_get/0 (lib/test.ex:7)

    5:   end
    6:   def call_get() do
    7:     require IEx; IEx.pry
    8:     get("k")
    9:   end
pry(1)> get("a")
:undefined
pry(2)> Test.get("a")
Doing get
:ok

As it is visible, calling get/1 from debugger results in executing built-in get/1 and put/2 instead of function from my Test module. To work it properly I need to namespace my function call. Could anyone explain me this behaviour?

1

There are 1 answers

2
Aleksei Matiushkin On

What happening here is: the context differs. Look:

iex|1 ▶ defmodule Test do
...|1 ▶   def get(p), do: p                            
...|1 ▶   IO.inspect quote do: (def get(), do: get(42))
...|1 ▶ end
{:def, [context: Test, import: Kernel],
 [{:get, [context: Test], []}, [do: {:get, [], '*'}]]}

The AST of get/0 function would include the context:

{:get, [context: Test], []}

This is how the compiler knows what to call for unqualified functions. Basically, the ability to call a function from within the same module unqualified is a syntactic sugar. While in a breakpoint, the module is already compiled and there is surely no access to “local” functions since there are no “local” functions anymore. You might import Test to gain an access to the functions by their unqualified names.