There are two worlds because there are two times when code is executed:
- At compile time (any code, which is not a function body is executed + macros)
- At runtime (Function bodies are executed)
Take this example:
defmodule A do
for {i, level} <- %{1 => :err, 2 => :warn, 3 => :info} do
def log_level(i), do: level
end
end
For the function log_level
what do you expect i
and level
to represent?
Basically it’s 3 times this: def log_level(i), do: level
, and it would complain about unmatchable clauses (all match i
) as well as crash at runtime for an undefined variable level
.
This is where unquoting comes in.
defmodule A do
for {i, level} <- %{1 => :err, 2 => :warn, 3 => :info} do
def log_level(unquote(i)), do: unquote(level)
end
end
At compile time this will define a module A with 3 function heads looking like that:
def log_level(1), do: :err
def log_level(2), do: :warn
def log_level(3), do: :info
The runtime will never know of i
and level
and therefore not fail because of undefined variables. The same thing happens in macros, where you also create AST at compile time. Macros can however also edit AST.
You might be wondering why this example doesn’t use a quote
like macros do. For a module it’s clear which code is compile time executed and which isn’t (only function bodies aren’t executed at compile time), so all the quote/unquote stuff happens as part of the defmodule
implementation. For macros there needs to be a distinction between code executed at compile time and the code it actually generates. To not have you manually edit AST nodes there’s quote
. It takes its body and converts the contents into AST. It’s basically a AST generator. quote
has the same problem as I explained above for the module body, therefore it uses unquote
as well, to put data you have at compile time “hard coded” into the generated AST.
The complexity really hits if you want to create the module body from my example (those unquote
s are usually named unquote fragments) within the quote
of a macro. This is where you need to use the bind_quoted
option for quote
to remove the ambiguity.