Hi, I am not sure if this is the right place for meta programming questions. Please redirect me if you think there is a better place to ask this question.
I am trying to understand the use of $(esc())
in macro definitions. I read the following source to learn about it.
Source1,
Source2.
My understanding is that in order to keep macro hygiene, I need to use esc
to keep global space variables seperate from local variables.
So I wrote the following macro, and expanded it to see the result.
Julia> n = 1
Julia>
macro esc_example(a)
quote
n = 3
println(n)
println($n)
println($(esc(n)))
println($a)
println($(esc(a)))
end
end
Julia> @esc_example(n)
3
1
1
3
1
Julia> macroexpand(:(@esc_example(n)))
quote # REPL[48], line 3:
#33#n = 3 # REPL[48], line 4:
(Main.println)(#33#n) # REPL[48], line 5:
(Main.println)(1) # REPL[48], line 6:
(Main.println)(1) # REPL[48], line 8:
(Main.println)(#43#n) # REPL[56], line 9:
(Main.println)(n)
end
I defined n
as 1 in REPL, and a local variable n
as 3.
I am not sure if esc() can be used on macro arguments, so I want to test it as well.
Let me go through it line by line, left side is the macro definition, and right side is the macro expansion .
-
n = 3
=>#33#n = 3 # REPL[48], line 4:
n
is defined locally as 3, so when expanding macro, the name is reassigned with a name#33#n
to make sure it does not collide with names in global space. I think this one is straight forward. -
println(n)
=>(Main.println)(#33#n) # REPL[48], line 5:
Just prints out the localn
value, understood. -
println($n)
=>(Main.println)(1) # REPL[48], line 6:
$n
is string interpolation. Replacingn
in global space with its value 1.
This one is a little confusing because I thought I have to use $(esc(n)) to get the value of n in global space. -
println($(esc(n)))
=>(Main.println)(1) # REPL[48], line 8:
This is the use of esc(). and it is getting the value ofn
from global space. Understood. But I thought the macro expansion will replace it with something likeMain.n
, rather than the value 1, because it should not be evaluated at macro expand time. Am I right? And if they have the same effect, what is the benefit of usingesc()
? -
println($a)
=>(Main.println)(#43#n) # REPL[56], line 9:
I think this line is a bug. Because this line should prints out the value ofa
, which isn
in global space, the value 1. But instead it is replaced with the localn
. -
println($(esc(a)))
=>(Main.println)(n)
Like I said in the before, I don’t know ifesc()
can be used on arguments so I am trying it out.
I was expecting an error, but it was replaced withn
in global space. Maybe someone can help me understand this part.
Here is the version info from Julia
julia> versioninfo()
Julia Version 0.6.3
Commit d55cadc350 (2018-05-28 20:20 UTC)
Platform Info:
OS: macOS (x86_64-apple-darwin14.5.0)
CPU: Intel(R) Core(TM) i5-6500 CPU @ 3.20GHz
WORD_SIZE: 64
BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell)
LAPACK: libopenblas64_
LIBM: libopenlibm
LLVM: libLLVM-3.9.1 (ORCJIT, skylake)
I apologize for the long post. I am trying my best to explain my confusion.
And thank you for reading through my question.