Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can `unquote` be called outside a macro?

Tags:

elixir

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?

like image 430
Nathan Long Avatar asked Nov 30 '25 02:11

Nathan Long


2 Answers

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.

like image 196
michalmuskala Avatar answered Dec 05 '25 18:12

michalmuskala


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

like image 32
Gazler Avatar answered Dec 05 '25 18:12

Gazler



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!