I have a macro works if defined in main.
macro check_set(d,v)
nm = string(v)
quote
global $v
if haskey($d,$nm)
$v = $d[$nm]
end
end
end
However, when I put it inside a Module (macro defined inside the module) to use in a function (also defined inside the module), I get scope issues.
export setVars
function setVars(val::Dict)
global max_iter
@check_set val max_iter
end
In main I call setVars(config)
where config
is a dictionary as expected. I get:
ERROR: UndefVarError: val not defined
Adding @macroexpand
I see:
begin
#= /home/dpazzula/Documents/Stuff/src/Stuff.jl:156 =#
global max_iter
#= /home/dpazzula/Documents/Stuff/src/Stuff.jl:157 =#
if Stuff.haskey(Stuff.val, "max_iter")
#= /home/dpazzula/Documents/Stuff/src/Stuff.jl:158 =#
Stuff.max_iter = Stuff.val["max_iter"]
end
end
So the ERROR makes sense, it is looking for Stuff.val
when val
is locally scoped to the function.
How do I get it to look for the locally scoped val
?
Your issue is related to macro hygiene. In your case, since you want d
and v
to refer to variable names in the scope of the macro call environment, you must "escape" them with esc
Here would be a minimal working example along the lines of what you wrote:
module Stuff
macro check_set(d,v)
nm = string(v)
d = esc(d)
v = esc(v)
quote
global $v
if haskey($d,$nm)
$v = $d[$nm]
end
end
end
end #module Stuff
We can check that this expands to what is expected:
julia> @macroexpand Stuff.@check_set val max_iter
quote
#= REPL[1]:8 =#
global max_iter
#= REPL[1]:9 =#
if Main.Stuff.haskey(val, "max_iter")
#= REPL[1]:10 =#
max_iter = val["max_iter"]
end
end
And that it also behaves as expected at run time:
julia> function setVars(val::Dict)
Stuff.@check_set val max_iter
end
setVars (generic function with 1 method)
julia> config = Dict("max_iter" => 42)
Dict{String,Int64} with 1 entry:
"max_iter" => 42
julia> setVars(config)
42
julia> max_iter
42
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With