Sorry about the title, this was the best I could come up with!
I’m not sure but this could be a slightly weird thing I am trying to do here, but I do not understand what is causing this behaviour.
I’m sure code will describe what I am attempting better than a description.
If you run the following code
defmodule Example.Base do
defmacro __using__(opts) do
quote do
defmodule Sub do
def sub_output do
IO.puts unquote(opts[:module])
end
end
def output do
IO.puts unquote(opts[:module])
end
end
end
end
defmodule Example do
use Example.Base, module: __MODULE__
end
Example.output
Example.Sub.sub_output
You will get the following output
Elixir.Example
Elixir.Example.Sub
Does anyone know why the context of opts[:module]
changes when being unquoted inside of a module definition?
p.s. sorry for lack of a good description, I am hoping a simple code example will speak for itself here 
3 Likes
You mean why your module, which is obviously Example
turned to be Example.Sub
? 
If you don’t want to change the input you inserted from outside world to macro use bind_quoted [opts: opts]
like this
quote bind_quoted: [opts: opts] do
# your code
end
3 Likes
The problem is that __MODULE__
is a call (a macro call, if I’m correct), so when you call a macro (like __using__
) passing it as a parameter, you are not passing it’s value, but the code that makes the call (in Elixir’s AST: {:__MODULE__, _meta, nil}
).
When you use unquote
, you are evaluating the code inside of it in the macro definer environment (Example.Base
). In your case, that translates to injecting the code that calls __MODULE__
(since opts[:module]
, in the macro definer environment, evaluates to that), and as one calls happens in the submodule and other in the main module, they output different values.
The bind_quoted
solution provided by @PatNowak works perfectly, as it evaluates the code in the macro caller environment:
IO.inspect opts[:module] # => {:__MODULE__, _some_meta, nil}
quote bind_quoted: [opts: opts] do
IO.inspect opts[:module] # => Example
# Rest of your code
end
Just to make the unquote
evaluation a bit clearer, if you replace your IO.puts
calls to something like this in your code:
IO.puts unquote(__MODULE__)
You would get this output:
Elixir.Example.Base
Elixir.Example.Base
Understanding these evaluation semantics of macros helped me a lot in understanding them 
5 Likes
Ah that makes complete sense, I thought it would evaluate the __MODULE__
at the point it calls into the __using__
macro.
Thanks to both of you for your help 
3 Likes