Help with macro calling another macro

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
5 Likes