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:
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
.
By requiring MyMacros, the module MyModule should know the existence of both macros. Therefore I should be able to use any macros.
The misunderstanding is here. :) require
only makes the module available to the compiler, it does not import the module functions. If you used import MyModule
then it would work.
However, it would be best to fix the issue by prefixing the module name, because then you allow developers using your code to use your macros explicitly (with require
) or by importing them.
Another option is to avoid multiple macro invocations like this:
defmodule MyMacros do
defmacro print_expr(expr) do
quoted_print_expr(expr)
end
defmacro print_hashes_around(expr) do
quote do
IO.puts "###"
unquote(quoted_print_expr(expr))
IO.puts "###"
end
end
defp quoted_print_expr(expr) do
quote do
IO.puts(unquote(expr))
end
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With