h unquote says it "Unquotes the given expression from inside a macro."
However, I've just seen a way that unquote can be used outside a macro.
defmodule Example do
x = 4
def foo do
unquote(x)
end
x = 5
def bar do
x = 4
"#{unquote(x)}, #{x}"
end
end
IO.puts Example.foo #=> 4
IO.puts Example.bar #=> "5, 4"
Is this the same unquote, or a different one? Is this a feature or a bug? (It seems to overlap with the "temporary storage" purpose of module attributes.)
Why can I call unquote outside a macro quote?
The simplest answer is that everything in a module is inside an implicit quote.
In particular this is done in the definition of defmodule (which is just a regular macro): https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/kernel.ex#L3008
Why is this needed? Elixir compiler works on the AST and the only way to get an AST is to quote the code.
Disclaimer: This is my understanding of what's happening. The truth about why it's done like this might be different.
This works because def itself is a macro implemented with defmacro and returns a quoted expression. So whilst it appears you are not inside of a quoted expression as you don't call quote, you actually are.
https://github.com/elixir-lang/elixir/blob/928302a912e397917be957142a9837ae58610207/lib/elixir/lib/kernel.ex#L3225L3227
There are other places where this holds true, for example inside ExUnit tests (again because the test macro uses def to define a function. https://github.com/elixir-lang/elixir/blob/928302a912e397917be957142a9837ae58610207/lib/ex_unit/lib/ex_unit/case.ex#L256
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With