What do Elixir's quote and unquote do (metaprogramming)? 🤔
Notes
If you’ve ever used a use
macro (who hasn’t!), or even created your own
__using__
macro, you’ll have noticed that we use quote
and typically
unquote
a lot.
def MyModule do
defmacro __using__(opts) do
quote do
# code here
# unquote(some_var)
end
end
end
Why is that?
The __using__/1
macro (and all macros, for that matter) take in and return
Elixir’s AST. quote/1
transforms regular Elixir into its AST form. That lets
us write code in a nice format, and quote/1
takes care of transforming it for
us.
Take a look:
iex> quote do: %{hello: "world"}
# => {:%{}, [], [hello: "world"]}
As you can see, most of Elixir’s AST is represented by 3-tuples (some values like atoms are represented as themselves).
What happens when we define a variable?
iex> quote do: %{hello: name}
# => {:%{}, [], [hello: {:name, [], Elixir}]}
You can see that the variable itself is part of the abstract syntax tree. But what if we want to inject a value instead?
That’s when unquote/1
comes in:
iex> name = "Aragorn"
iex> quote do: %{hello: unquote(name)}
# => {:%{}, [], [hello: "Aragorn"]}
As you can see, we can tell the compiler to inject the value of name
instead
of transforming name
into its AST (which is {:name, [], Elixir}
.
Since macros receive and return quoted expressions, we tend to see quote/1
as
the last thing we invoke in the macro.