I am experimenting with Macros in elixir. Therefore, the code I'm about to show should certainly be done with simple functions but.. I'm experimenting !
I want to define 2 macros (A and B) and make A use B to experiment with macro expansion. When I use A, I get a compile error saying that the function B is undefined.
Here is the code:
defmodule MyMacros do
defmacro print_expr(expr) do
quote do
IO.puts(unquote(expr))
end
end
defmacro print_hashes_around(expr) do
quote do
IO.puts "###"
print_expr(unquote(expr))
IO.puts "###"
end
end
end
defmodule MyModule do
require MyMacros
def my_print(expr) do
MyMacros.print_hashes_around(expr)
end
end
MyModule.my_print("hello world")
And here is the compile error:
macro_test.exs:17: warning: redefining module MyModule
** (CompileError) macro_test.exs:21: function print_expr/1 undefined
(stdlib) lists.erl:1336: :lists.foreach/2
macro_test.exs:17: (file)
(elixir) lib/code.ex:307: Code.require_file/2
The way I (mis)understand things:
- By requiring MyMacros, the module MyModule should know the existence of both macros. Therefore I should be able to use any macros.
- When print_hashes_around is expanded in MyModule, the compiler should find that print_expr is also a macro. Therefore, another expansion should happen.
- What seems to happen is that second expansion does not happen. Therefore the compiler looks for a function definition that does not exist.
Am I right ?
As suggested in slack, prefixing print_expr
with MyMacros.
fixes it. I still don't understand why. MyModule
requires MyMacros
so both Macros should be known and expandable... When I look at the definition of unless
, it uses if
, not Kernel.if
.