LoginSignup
23
17

More than 5 years have passed since last update.

Elixirのdefmacro内の__MODULE__はどのモジュールを指しているのか

Posted at

Elixirのdefmacro内のコードには__MODULE__というマクロが頻出しますが、これが「マクロが定義されているモジュール」を指しているのか、それとも「マクロを呼び出しているモジュール」を指しているのか、ちょっと分かりにくいので下記のように実験してみました。

defmodule A do
  defmacro __using__(_opts) do
    IO.inspect "__MODULE__ = #{__MODULE__}"
    IO.inspect "unquote(__MODULE__) = #{unquote(__MODULE__)}"
    quote do
      IO.inspect "__MODULE__ = #{__MODULE__}"
      IO.inspect "unquote(__MODULE__) = #{unquote(__MODULE__)}"
      @before_compile unquote(__MODULE__)
    end
  end
  defmacro __before_compile__(env) do
    IO.inspect "env.module == #{env.module}"
  end
end

defmodule B do
  use A
end

iex上での実行結果は下記のようになります。

"__MODULE__ = Elixir.A"
"unquote(__MODULE__) = Elixir.A"
"__MODULE__ = Elixir.B"
"unquote(__MODULE__) = Elixir.A"
"env.module == Elixir.B"

要するに、defmacro内のquote式内で__MODULE__と書いた場合のみ呼び出し側のモジュールが参照され、それ以外の場合はマクロが定義されているモジュールが参照される、ということになるようです。

attributeを操作する関数(Module.register_attribute等)を使う場合は「呼び出し側のモジュール」を参照する必要がありますが、それ以外は基本的に「マクロが定義されているモジュール」を参照するケースの方が多いと思いますので、「基本的にはunquote(__MODULE__)を使う、attributeを操作するときだけ__MODULE__を使う」というような覚え方でも良さそうな印象です。

23
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
17