How to access module attributes in a macro outside `quote`?

It doesn’t, rather putting it in a quote moves the actual attribute lookup from compile-time to run-time. :slight_smile:

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.