Multiple quote blocks in a macro

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

Nothing pressing, just don’t understand it :slight_smile:

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
8 Likes

So simple. Duh. Thanks.