tkowal
tkowal

Reputation: 9299

Why is the error on the wrong line?

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

Answers (1)

José Valim
José Valim

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

Related Questions