It doesn’t, rather putting it in a quote moves the actual attribute lookup from compile-time to run-time.
That’s a useful distinction, but I don’t understand why code outside the quote
is evaluated at compile-time while code inside it is evaluated at runtime.
For example, consider this module:
defmodule MyModule do
k = 1 + 2
IO.puts("In #{__MODULE__}: #{k}")
end
According to my understanding, this code is evaluated at compile time, not run time. In fact, if I run mix compile
on it, it prints MyModule: 3
confirming that it is evaluated as part of compilation (which is what “compile time” is, right?). If I move that code into a macro outside a quote
, it produces the same result:
defmodule MyMacros do
defmacro print_stuff do
module = __CALLER__.module
k = 1 + 2
IO.puts("In #{module}: #{k}")
end
end
defmodule MyModule do
require MyMacros
MyMacros.print_stuff
end
Again, when I run mix compile
, it prints MyModule: 3
, confirming the code is evaluating at compile time.
So in what sense is code in a macro outside of a quote
not evaluated at compile time, given it evaluates as part of compilation?
Really? It works here:
That’s interesting your example worked. Here’s what I had tried:
(For some reason, I can’t get this to format how I want: I put the quote and my reply in separate paragraphs but the forum is collapsing it into the prior paragraph. Any idea why?)
defmodule MyMacros do
defmacro __using__(_) do
quote do
Module.register_attribute(__MODULE__, :foo, persist: true)
end
end
defmacro my_macro() do
module = __CALLER__.module
Module.get_attribute(module, :foo) |> IO.inspect(label: "outside quote")
quote do
Module.get_attribute(unquote(module), :foo) |> IO.inspect(label: "with unquoted module")
Module.get_attribute(__MODULE__, :foo) |> IO.inspect(label: "with __MODULE__")
end
end
end
defmodule UseMacros do
use MyMacros
Module.put_attribute(__MODULE__, :foo, bar: 1)
MyMacros.my_macro()
end
Basically, just replacing @foo bar: 1
with Module.put_attribute(__MODULE__, :foo, bar: 1)
.
I need to play around with your some more to see why it works while mine doesn’t.