Julia Macro Hygiene
Macro hygiene is the rule that keeps names a macro creates apart from the caller's names. Escaped names are the exception to that rule.
A macro name does not change the caller's variable
The macro creates a name of its own. The caller's x keeps its first value.
macro setlocal()
return :(x = 50)
end
x = 1
println(@setlocal())
println(x)An escaped name changes the caller's variable
Escaping marks a name as the caller's own name. The caller's x then takes the new value.
macro setcaller()
return :($(esc(:x)) = 50)
end
x = 1
println(@setcaller())
println(x)Gensym makes a fresh name each time
Two fresh names are never equal. That freshness stops a temporary name from clashing with a caller's name.
a = gensym(:tmp)
b = gensym(:tmp)
println(a == b)
println(typeof(a))Example
macro setlocal()
return :(x = 50)
end
macro setcaller()
return :($(esc(:x)) = 50)
end
macro addtemp(ex)
t = gensym(:t)
return :($t = $(esc(ex)); 2 * $t)
end
x = 1
println(@setlocal())
println(x)
println(@setcaller())
println(x)
v = 6
println(@addtemp v)Key points
- Hygiene: names a macro creates stay separate from the caller's names.
- Escape: use esc to mark a name as the caller's own name.
- Gensym: gensym makes a fresh name that cannot clash with a caller's name.
- Local name: a macro name without esc leaves the caller's value unchanged.
- Caller name: an escaped name changes the caller's value.
In this example, the first macro leaves the caller's x at 1. The escaped macro then sets it to 50. The last macro uses gensym for a fresh temporary name to double 6.
Note
a fresh temporary name inside a macro keeps its work apart from the caller's names.
Try it Yourself
Edit the code, then press Run.
Running is simulated · JuliaHub
Exercise
A macro sets a name without esc, and the caller already has that name. What happens to the caller's value?