I was following along this notebook (originally written in Julia 0.x, I am using Julia 1.7.1). One of the cells defines the following macro.
macro twice(ex)
quote
$ex
$ex
end
end
On the very next cell, this macro is invoked.
x = 0
@twice println(x += 1)
Replicating this in the REPL (for brevity) results in the following error.
ERROR: syntax: invalid assignment location "Main.x" around REPL[1]:3
Stacktrace:
[1] top-level scope
@ REPL[4]:1
So, I understand that x += 1
is somehow causing this problem, but after going through the docs (metaprogramming), I could not figure out why exactly this is an invalid assignment or how to fix this.
@macroexpand @twice println(x += 1)
successfully returns the following.
quote
#= REPL[1]:3 =#
Main.println(Main.x += 1)
#= REPL[1]:4 =#
Main.println(Main.x += 1)
end
So, I tried eval
ing this in the top-level without the Main.
s, and it evaluates successfully.
x = 0
eval(quote
println(x += 1)
println(x += 1)
end)
Output:
1
2
But, if I add the module name explicitly, it throws a different error.
eval(quote
Main.println(Main.x += 1)
Main.println(Main.x += 1)
end)
ERROR: cannot assign variables in other modules
Stacktrace:
[1] setproperty!(x::Module, f::Symbol, v::Int64)
@ Base ./Base.jl:36
[2] top-level scope
@ REPL[14]:3
[3] eval
@ ./boot.jl:373 [inlined]
[4] eval(x::Expr)
@ Base.MainInclude ./client.jl:453
[5] top-level scope
@ REPL[14]:1
I tried a few other things, but these are the only things that I think might be getting somewhere.
eval
ing in the top-level with the module Main
specified fails?Use esc
(This "prevents the macro hygiene pass from turning embedded variables into gensym variables"):
julia> macro twice(ex)
esc(quote
$ex
$ex
end)
end;
julia> x=1
1
julia> @twice println(x += 1)
2
3