Julia Macro Systems
A macro system is a macro that takes a whole block, uses safe introduced names, and expands into several statements. Safe introduced names never clash with caller names.
One macro call can run a statement twice
The macro expands into the escaped statement two times in order.
macro twice(stmt)
return quote
$(esc(stmt))
$(esc(stmt))
end
end
count = 0
@twice count += 1
println(count)A fresh name leaves the caller variable alone
The macro stores 5 in a fresh name, adds 100, and the caller variable named tmp stays 7.
macro add_temp(val)
t = gensym()
return quote
$t = $(esc(val))
$t + 100
end
end
tmp = 7
println(@add_temp 5)
println(tmp)A macro can take a whole block
The macro expands into the escaped block two times in order.
macro run_twice(block)
return quote
$(esc(block))
$(esc(block))
end
end
count = 0
@run_twice begin
count += 1
end
println(count)Example
macro swap(a, b)
t = gensym()
return quote
$t = $(esc(a))
$(esc(a)) = $(esc(b))
$(esc(b)) = $t
end
end
x = 1
y = 2
@swap x y
println(x)
println(y)Key points
- Whole block: A macro can take a whole block as its input, not just one value.
- Escaped names: esc marks a name as belonging to the caller, so it keeps its caller meaning.
- Fresh name: gensym makes a name no caller code can clash with.
- Several statements: One macro call can expand into several statements in order.
- Use a fresh name for a temporary value a macro introduces, and escape caller names.
In this example, the macro stores x in a fresh name, copies y into x, copies the fresh name into y, and the printed values show the swap.
Note
A temporary name made with gensym stays separate from a caller variable with a plain name.
Try it Yourself
Edit the code, then press Run.
Running is simulated · JuliaHub
Exercise
Why does a macro use a fresh name for a temporary value?