Почему отладчик elixir вызывает встроенную функцию вместо моей, если они имеют одинаковые имена

Вот простой модуль с двумя точками останова в функциях, которые вызывают другие функции с именами, точно такими же, как встроенные: get/1 а также 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

Выполнение этого в оболочке:

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

Как видно, звонит get/1 от отладчика приводит к выполнению встроенного get/1 а также put/2 вместо функции от моего Test модуль. Для правильной работы мне нужно пространство имен для вызова моей функции. Может ли кто-нибудь объяснить мне это поведение?

1 ответ

То, что здесь происходит: контекст отличается. Посмотрите:

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, [], '*'}]]}

АСТ get/0 функция будет включать контекст:

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

Так компилятор знает, что вызывать для неквалифицированных функций. По сути, возможность вызывать функцию из одного и того же модуля без оговорок является синтаксическим сахаром. Находясь в точке останова, модуль уже скомпилирован, и, безусловно, нет доступа к "локальным" функциям, поскольку больше нет "локальных" функций. Ты можешь import Test получить доступ к функциям по их неквалифицированным именам.

Другие вопросы по тегам