It’s almost never necessary or helpful to use eval in a macro. A macro takes code (not the values represented by that code) and produces new code, so it shouldn’t need to eval anything.
It seems like you don’t need a macro at all–using a function solves the problem perfectly:
function gk(x)
keys(x)
end
(or, at that point, don’t even define gk at all and just call keys yourself).
Can you explain more about the problem you actually want to solve?
macro unp(x)
local nt = @eval $x
for k in keys(nt)
local v = nt[k]
@eval $k = $v
end
end
p = (a=1, b="b")
julia> @unp p
julia> a
1
julia> b
"b"
Unpack a NamedTuple and create new variables in the calling scope. I know, that’s unsafe, and it is not that I actually need it, but I’m curious how can that be done. In the example above it works. How can that be done if the macro called in a different scope?
Yes, indeed, I don’t need a macro here, just function:
function unp(x)
exs = [Expr(:(=), k, QuoteNode(x[k])) for k in keys(x)]
eval.(exs)
end
p = (a=1, b="b")
julia> a
ERROR: UndefVarError: a not defined
julia> unp(p);
julia> a
1
julia> b
"b"
No, we mean that eval always evaluate on global scope, and therefore your function will always create global variables. If you call it inside a function it will not create variables local to the function, and if the function had any local variables of the same name they will be shadowing such global variables. What you see only work because you are working in global scope in the REPL.
julia> function unp(x)
exs = [Expr(:(=), k, QuoteNode(x[k])) for k in keys(x)]
eval.(exs)
end
unp (generic function with 1 method)
julia> function test_unp(p)
a = 10
b = "c"
unp(p)
@show a
@show b
return
end
test_unp (generic function with 1 method)
julia> test_unp((a=1, b="b"))
a = 10
b = "c"
julia> a
1
julia> b
"b"
Here you can see that the variables are global (appeared out of the function that called unp) and that the local variables shadowed them inside the function.
If we do not define a local a and a local b inside the test_unp function, then the function see the global variables, but I am not sure this works outside of the REPL. Julia has something called “Age of the world” that sometimes prevents things just evaluated to be used immediately in the sequence.
OP everyone in this thread is correct, you should not be using eval ever. It is not though it works with expressions, in Julia using “metaprogramming” refers to re-writing expressions in local scope.
You may be interested in the following packages
StaticModules.jl which provides the macro @with for working with objects.