Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elixir - Calling / Invoking Macros - UndefinedFunctionError

Tags:

elixir

Why does Elixir report UndefinedFunctionError when calling a macro using Module.macroName syntax in an .exs file? I seem to able to call Macro only if I have another function that calls the macro and I call the function instead of macro.

Below code demonstrates this:

defmodule Sample do
  defmacro doIt(expression) do
    quote do
      IO.puts unquote(expression)
    end
  end

  def doFunc(e), do: doIt(e)
end

Sample.doFunc "Hello World via Function" # Works fine
Sample.doIt "Hello World from Macro!" # Gives error

Output

Hello World via Function
** (UndefinedFunctionError) undefined function: Sample.doIt/1
    Sample.doIt("Hello World from Macro!")
    (elixir) lib/code.ex:307: Code.require_file/2

The Elixir documentation example uses iex, instead of calling macro in the .exs file. Even above code, if we remove calls to Sample.doIt and load it in iex, and then call Sample.doIt works fine.

E:\elixir>iex hello.exs
Hello World via Function
Interactive Elixir (1.0.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> require Sample
nil
iex(2)> Sample.doIt "Hello"
Hello
:ok
iex(3)>

If I try to require Sample in my file above, like below

defmodule Sample
  ... rest of stuff as shown above ...
end

require Sample

Sample.doFunc "Hello World via Function"
Sample.doIt "Hello World from Macro!"

I get error

** (CompileError) hello.exs:11: module Sample is not loaded but was defined. This happens because you are trying to use a module in the same context it is defined. Try defining the module outside the context that requires it.
    (stdlib) lists.erl:1352: :lists.mapfoldl/3
    (stdlib) lists.erl:1353: :lists.mapfoldl/3
like image 379
Wand Maker Avatar asked Aug 08 '15 17:08

Wand Maker


1 Answers

As usual you need to require a module before using its macros to signify to the compiler the order of compilation of the modules:

defmodule Other do
  def run do
    require Sample

    Sample.doFunc "Hello World via Function"
    Sample.doIt "Hello World from Macro!"
  end
end

Other.run # => Hello World via Function
          #    Hello World from Macro!
like image 167
Paweł Obrok Avatar answered Oct 18 '22 14:10

Paweł Obrok