In short, you're missing the notion of macro
hygiene and
in particular the esc
function.
Although this part of the documentation is a good read for anyone wanting to develop their own macros, let's try to expand a little on what macro hygiene does in this particular example, and how you can fix things.
A useful way to debug macros is provided by
@macroexpand
:
julia> @macroexpand @dbg "initialization" begin
foo = rand(10)
println("foo = ", foo)
end
quote
#= REPL[1]:3 =#
var"#32#title" = "initialization"
#= REPL[1]:4 =#
Main.println("Entering $(var"#32#title")")
#= REPL[1]:5 =#
begin
#= REPL[5]:2 =#
var"#33#foo" = Main.rand(10)
#= REPL[5]:3 =#
Main.println("foo = ", var"#33#foo")
end
#= REPL[1]:6 =#
Main.println("Leaving $(var"#32#title")")
end
Leaving aside all comments within #= ... =#
markers, we see almost the code we
wanted to get: the user code block has been surrounded with statements printing
the "Entering" and "Leaving" notifications. However, there is one notable
difference: variable names like foo
or title
have been
replaced with weirdly looking names like var"#33#foo"
or var"#32#title"
. This is what is called
"macro hygiene", and it helps avoiding clashes that could occur between the
variables used in the macro itself (like title
in this example), and the variables used in the code block
provided as an argument to the macro (like foo
here). (Think for example what
would happen if you used you @dbg
on a code block that defines a title
variable.)
Julia errs on the side of caution, and protects in this way all variables
appearing in the macro. If you want to disable this for selected parts of the
expression produced by the macro, you can wrap these subexpressions inside the
esc
function. In your example, you should for example escape the user-provided
expression:
macro dbg(block_title, expr)
quote
title = $block_title
println("Entering $title")
$(esc(expr))
println("Leaving $title")
end
end
Now things should work like want them to:
julia> @dbg "initialization" begin
foo = rand(10)
println("foo = ", foo)
end
Entering initialization
foo = [0.2955287439482881, 0.8989053281359838, 0.27751430906108343, 0.4920810199867245, 0.7633806735297282, 0.34535540650110597, 0.7099231627594489, 0.39978144801175564, 0.9104888704503833, 0.1983996781283539]
Leaving initialization
julia> @dbg "computation" begin
foo .+= 1
end
Entering computation
Leaving computation
julia> foo
10-element Array{Float64,1}:
1.295528743948288
1.8989053281359838
1.2775143090610834
1.4920810199867245
1.7633806735297282
1.345355406501106
1.709923162759449
1.3997814480117556
1.9104888704503833
1.198399678128354