@colinclout12
You practically never have to gensym
anything by hand. @pdeffebach `s approach is generally recommended but does not work as expected when you need to introduce local variables, because the esc
works over the whole expression.
What you want to do is only esc
what needs to be evaluated in the calling scope. This should work for your modified nif + 5
, but feel free to point me to problems with this approach if you find any:
julia> macro nif_plus_five(expr, pos, zero, neg)
return quote
value = $(esc(expr)) + 5
if value > 0
return $(esc(pos))
elseif value == 0
return $(esc(zero))
else
return $(esc(neg))
end
end
end
@nif_plus_five (macro with 1 method)
julia> @nif_plus_five 3 "Positive" "Zero" "Negative"
"Positive"
julia> let x = "letted Positive"
@nif_plus_five -2 x "zero" "neg"
end
"letted Positive"
julia> let value = "This should not interefere with the output: Positive!"
@nif_plus_five 5 value "Zero" "Neg"
end
"This should not interefere with the output: Positive!"
julia> let value = "This should not interefere with the output: Positive!"
@macroexpand @nif_plus_five 5 value "Zero" "Neg"
end
quote
#= REPL[5]:3 =#
var"#5#value" = 5 + 5
#= REPL[5]:4 =#
if var"#5#value" > 0
#= REPL[5]:5 =#
return value
elseif #= REPL[5]:6 =# var"#5#value" == 0
#= REPL[5]:7 =#
return "Zero"
else
#= REPL[5]:9 =#
return "Neg"
end
end
This automatically gensym
s value
because you assign to it, but you can also write local value
when you assign to it the first time just to be sure.
If you still find you need to manually handle gensym
names, you have to declare them outside of the quote
expression you return, then you can use them like normal variables. First with liberally escaping and without gensym, to confirm that this is a dirty
macro normally:
julia> macro nongensymmed(left, right)
return esc(quote
value = $(left) + $(right)
end)
end
@nongensymmed (macro with 1 method)
julia> let value = 2
println("Value: $value")
solution = @nongensymmed 3 5
println("Solution: $solution")
println("Value after macro: $value")
end
Value: 2
Solution: 8
Value after macro: 8
And now with a gensym
name for value
(you don’t need to specify a name in the gensym
, it’s only changing the base of the name). You declare it before quote
and interpolate it where you need it as usual:
julia> macro gensymmed(left, right)
value = gensym("value")
return esc(quote
$(value) = $(left) + $(right)
@show $(value)
end)
end
@gensymmed (macro with 1 method)
julia> let value = 2
println("Value: $value")
solution = @gensymmed 3 5
println("Solution: $solution")
println("Value after macro: $value")
end
Value: 2
var"##value#246" = 8
Solution: 8
Value after macro: 2