0

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?

mkorszun
  • 4,461
  • 6
  • 28
  • 43
  • 1
    I don't think the current module's functions are automatically "imported" in a `IEx.pry` session. You could just do `import Test` when the session starts. – Dogbert Sep 08 '17 at 12:39

1 Answers1

2

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.

Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
  • 1
    I don't think "the ability to call a function from within the same module unqualified" is "syntactic sugar" because the behavior of the two things is not the same. See fully qualified function calls vs regular calls as explained here: https://stackoverflow.com/questions/32923026/using-fully-qualified-function-calls-in-erlang. – Dogbert Sep 08 '17 at 15:59
  • I also get the exact same AST when I run `quote do: (def get(), do: get(42))` from inside `defmodule Test` like you did and if I run it from the iex session that OP's code starts, so I don't think this is the reason why local calls don't work. I do get an AST with `context: Elixir` if I run the code in a brand new `iex` session. – Dogbert Sep 08 '17 at 16:01