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?