Hi Everyone,
I’ve just started learning about metaprogramming in Elixir, and I’m having trouble with one of the key concepts of context.
I wrote up this small gist, where I define a module (UseMacro
) that uses another module (DefineMacro
), and thereby invokes __using__/1
on DefineMacro
.
Can someone help me understand why Line 7, Line 10, and Line 11 resolve to the values that they do (DefineMacro
, UseMacro
, and DefineMacro
, respectively)?
Thank you.
[EDIT]
I think I’m ok with Line 7. If I think of a macro as a function, there is nothing there that is surprising.
If I think about quote
as returning an AST, then I can see how Line 10 resolves to UseMacro
. I can almost “copy and paste” the code returned by quote
where I used the use DefineMacro
.
I am still very confused on how Line 11 resolves to DefineMacro
. If I copied that line into UseMacro
, again, in place of use DefineMacro
, I would not expect it to resolve to DefineMacro
.
2 Likes
By way of analogy, you can think of quote do end
as starting a block of text like
"""
Hello!
"""
unquote
is sorta like #{}
string interpolation IE
text = "goodbye!"
"""
Hello!
#{text}
"""
That will be
Hello!
goodbye!
Leaving the analogy, quote do
does not do anything particularyl magical, you can think of it like a function that takes a block of code and returns AST. You can see this by simply doing: (note the IO.inspect after the quote do end
)
defmodule DefineMacro do
defmacro __using__(_opts) do
IO.inspect __MODULE__ # DefineMacro
quote do
IO.inspect __MODULE__ #UseMacro
IO.inspect unquote(__MODULE__) #DefineMacro
end
|> IO.inspect
end
end
what unquote(val)
does is simply say "hey, instead of turning this code into AST, simply stick it in there as is.`
Does that help?
5 Likes
That is incredibly helpful! Thank you @benwilson512.
2 Likes
Explaining quote
as creating a string and unquote
as the interpolation is really clicking. quote
starts an AST (a.k.a. string) and unquote
puts / interpolates the value straight into the AST.
3 Likes