8

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

1 Answer 1

6

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!
Sign up to request clarification or add additional context in comments.

3 Comments

Here too, you defined a function run in another module in order to use the Sample.doIt - is this the only way to use a macro - call it via another function which is enclosed in a Module
That seems to be a limitation of the compiler. As the error says - you can't use Macros from a module in the same context where the module is defined. I'm guessing it has to do with how the compiler orders things for compilation.
Yes, exactly. The macros are expanded at compile time so when we parse defmodule Foo followed by Foo.some_macro, we still haven't compiled Foo, so we have no idea how to expand the macro.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.