🎓 A1Learner
🔍
0 of 46 lessons completed

Elixir Macro Hygiene

Macro hygiene keeps a macro's variables separate from the caller's variables. The escape hatch var! is the deliberate way to reach the caller's variable.

A macro variable does not leak

The caller starts with value 1. The macro sets its own value to 99.

defmodule SetterMacro do
  defmacro set_value do
    quote do
      value = 99
    end
  end
end
defmodule SetterCaller do
  require SetterMacro
  def run do
    value = 1
    SetterMacro.set_value()
    value
  end
end
IO.puts(SetterCaller.run())

A temporary name stays inside the macro

The macro uses temp for its own work. The caller's temp is untouched.

defmodule TempMacro do
  defmacro double_with_temp(x) do
    quote do
      temp = unquote(x) * 2
      temp + 1
    end
  end
end
defmodule TempCaller do
  require TempMacro
  def run do
    temp = 100
    result = TempMacro.double_with_temp(10)
    {result, temp}
  end
end
IO.inspect(TempCaller.run())

var! reaches the caller variable

With var!, the macro sets the caller's value on purpose.

defmodule BangMacro do
  defmacro set_value_bang do
    quote do
      var!(value) = 99
    end
  end
end
defmodule BangCaller do
  require BangMacro
  def run do
    value = 1
    before = value
    BangMacro.set_value_bang()
    {before, value}
  end
end
IO.inspect(BangCaller.run())

Example

defmodule MixMacro do
  defmacro touch do
    quote do
      temp = 50
      temp
    end
  end
  defmacro set_score do
    quote do
      var!(score) = 77
    end
  end
end
defmodule MixCaller do
  require MixMacro
  def run do
    score = 10
    before = score
    temp = 5
    local = MixMacro.touch()
    MixMacro.set_score()
    {before, score, temp, local}
  end
end
IO.inspect(MixCaller.run())

Key points

  • Hygiene: a macro variable does not leak into caller code.
  • Caller variable: a variable in the caller keeps its own value after a macro runs.
  • Macro variable: a variable created inside a macro stays inside the macro.
  • Use var! to reach a caller variable on purpose from inside a macro.
  • Use var! only when the caller variable is the point of the macro.

In this example, the caller starts with score 10 and temp 5, the touch macro returns 50 from its own temp, and set_score uses var! to change the caller score to 77.

Note

var! breaks the separation, so it is used sparingly.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

A caller has value 1 and a macro sets its own value to 99. What is the caller value after the macro runs?