If you add multiple quote do ... end blocks in a macro, only the last one seems to actually get generated…unless the quote do ... end is inside a loop. I’d like to understand why the behaviour is different. For example, this code here will generate a print_b function, but not a print_a function.
defmacro setup_printers do
quote do
def print_a(), do: IO.inspect("print_a")
end
quote do
def print_b(), do: IO.inspect("print_b")
end
end
However, this generates both:
defmacro setup_printers do
for printer <- [:print_a, :print_b] do
quote do
def unquote(printer)(), do: IO.inspect(unquote(printer))
end
end
end
quote does returns an AST of its argument, but does not execute or evaluate anything.
To take your macro take effect, it has to return an AST. In your first version it does return the AST of the feinition of print_b/0 only, the one of print_a/0 has been generated but since it wasn’t assigned its lost. Its pretty much the same as writing the following:
def foo() do
2
4
end
You can achieve a similar effect as in your second version, by writing the following:
defmacro setup_printers do
quote do
def print_a(), do: IO.inspect("print_a")
def print_b(), do: IO.inspect("print_b")
end
end
or
defmacro setup_printers do
a = quote do
def print_a(), do: IO.inspect("print_a")
end
b = quote do
def print_b(), do: IO.inspect("print_b")
end
[a, b]
end