I have started to use Metaprogramming now. While my code is running, I noticed that there are some things that I do not understand. My understanding is that at the simplest level macros return an expression which is then evaluated. So, I tried to define a variable b and set its value to one using a macro:
macro test(x)
quote
b=1
end
end
When I then run in REPL:
b
Then I get an error message:
ERROR: UndefVarError: b not defined
The macro seems to return 1.
On the other hand if I type,
eval(Meta.parse(“b=1”))
Then b is defined in the REPL.
I would have expected the macro and the eval call to have the same effect. Apparently, there is something I am not understanding here…
Variables defined through macro get mangled so that they don’t accidentally overwrite other variables in the same context. You may use escaping with esc(b) within macro if you want to expose the name(s).
You can use esc to avoid the hygiene pass for certain variables or the entire expression.
julia> macro test()
quote
$(esc(:b))=1; nothing
end
end
@test (macro with 1 method)
julia> b
ERROR: UndefVarError: b not defined
julia> @test
julia> b
1
When working with macros, @macroexpand is your friend:
julia> @macroexpand @test
quote
#= REPL[1]:3 =#
b = 1
#= REPL[1]:3 =#
Main.nothing
end
julia> macro test2()
quote
b=1; nothing
end
end
@test2 (macro with 1 method)
julia> @macroexpand @test2
quote
#= REPL[6]:3 =#
var"#17#b" = 1
#= REPL[6]:3 =#
Main.nothing
end
Notice the mangled name of b in @test2.
Note that the number in the gensymed variable increases each time. Seeing 17 above, we can infer that it’ll be 18 next time: