Consider these 3 variants of a timing macro:
This one doesn’t escape anything, causing the user-defined variable to be left undefined:
julia> macro my_time(expr)
quote
start = time()
retval = $expr
println("Elapsed time: $(time() - start)s.")
end
end
@my_time (macro with 1 method)
julia> @my_time begin
sleep(1)
a = 42
end
Elapsed time: 1.0227389335632324s.
julia> start # This is good
ERROR: UndefVarError: start not defined
julia> a # But not this
ERROR: UndefVarError: a not defined
If you escape everything, user-defined names are correctly accounted for, but you lose hygiene: in this case for example the macro leaks the variables it uses internally and could cause name collisions with user-defined variables:
julia> macro my_time(expr)
quote
start = time()
retval = $expr
println("Elapsed time: $(time() - start)s.")
end |> esc
end
@my_time (macro with 1 method)
julia> @my_time begin
sleep(1)
a = 42
end
Elapsed time: 1.023123025894165s.
julia> a # This is fixed
42
julia> start # This should not be defined; it comes from the macro itself
1.637597519544262e9
Now this last version escapes only the user-provided code, making it more hygienic:
julia> macro my_time(expr)
quote
start = time()
retval = $(esc(expr))
println("Elapsed time: $(time() - start)s.")
end
end
@my_time (macro with 1 method)
julia> @my_time begin
sleep(1)
a = 42
end
Elapsed time: 1.0229160785675049s.
julia> a # OK
42
julia> start # OK
ERROR: UndefVarError: start not defined