Invalid assignment error inside Julia macro

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 evaling 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.

  • Why exactly is the assignment in the first macro code block invalid? Is it for the same reason that evaling in the top-level with the module Main specified fails?
  • How can this invalid assignment be circumvented, OR how do I port this to Julia 1.7?

>Solution :

Use esc:

julia> macro twice(ex)
         esc(quote
           $ex
           $ex
         end)
       end;

julia> x=1
1

julia> @twice println(x += 1)
2
3

Leave a Reply