Reputation: 9299
I am diving into Metaprogramming Elixir by Chris McCord.
I made a spelling mistake while typing one of examples:
defmodule Math do
defmacro say({:+, _, [lhs, rhs]}) do
qoute do #spelling mistake (swapped "o" and "u")
lhs = unquote(lhs) #(CompileError) math.exs:4: undefined function lhs/0
rhs = unquote(rhs)
result = lhs + rhs
IO.puts "#{lhs} plus #{rhs} is #{result}"
result
end
end
defmacro say({:*, _, [lhs, rhs]}) do
qoute do #spelling mistake copied
lhs = unquote(lhs)
rhs = unquote(rhs)
result = lhs * rhs
IO.puts "#{lhs} times #{rhs} is #{result}"
result
end
end
end
In the shell, the errors are meaningful:
iex(1)> qoute do: 1 + 2 #spelling mistake
** (RuntimeError) undefined function: qoute/1
iex(1)> unquote do: 1
** (CompileError) iex:1: unquote called outside quote
Why compiling this file gives error in the next line? Is my spelling mistake some valid construct?
The error appears in correct file, if I remove the unquote
.
defmodule Math do
defmacro say({:+, _, [lhs, rhs]}) do
qoute do #function qoute/1 undefined
result = lhs + rhs
IO.puts "#{lhs} plus #{rhs} is #{result}"
result
end
end
...
Why using unquote
moved the error somewhere else?
Upvotes: 3
Views: 104
Reputation: 51419
That's because once you call qoute/1
, Elixir assumes it is a function that will be defined later, and proceeds to compile the code as a function call. However, when we try to compile it, we see an unquote, assume there is a variable defined outside, and everything crashes when it doesn't.
There is no way we can work around it because the error happens when we are expanding code and is exactly when quote/unquote are expanded too.
Upvotes: 3