Quoting symbols in a local scope

How do symbols work in a local scope when quoted in a QuoteNode/Meta.quot/Expr(:quote), e.g. a for loop? This is a follow-up to my previous question. I want to add something to the docs that fills in the gaps I discovered through the series of links at the bottom of this question, but I just don’t feel like I understand what’s going on ‘under-the-hood’ anywhere near well enough to do it justice.

Defining a symbol variable and printing it works fine:

julia> asymbol = :a
:a

julia> @eval ($println)(asymbol)
a

But doing the same in a for loop yields an error, I’m guessing because @eval looks for the variable i in the global scope :

julia> for i in (:a,)
       @eval ($println)(i)
       end
ERROR: UndefVarError: i not defined
Stacktrace:
 [1] macro expansion at .\REPL[4]:2 [inlined]
 [2] anonymous at .\<missing>:?

Trying to interpolate i in the for loop also gives an error because then it looks for a in the global scope:

julia> for i in (:a,)
       @eval ($println)($i)
       end
ERROR: UndefVarError: a not defined
Stacktrace:
 [1] macro expansion at .\REPL[5]:2 [inlined]
 [2] anonymous at .\<missing>:?

But using Meta.quot works just fine, how is Meta.quot doing that?

julia> for i in (:a,)
       @eval ($println)( $(Meta.quot(i)))
       end
a

References:

These examples are something good to understand but they are not very good for explaining macro usage. The first error you get is due to eval evaluating in global scope, not due to the macro. In fact @eval have very different evaluation semantics than most other macros so you shouldn’t use it to understand macro’s evaluation rules in general.

Quoting symbols do NOT behave different in local scope, the only difference you observe above is due to eval. As for interpolation, quoting should generally preserve the indentity of the object, including symbols. They just may not be needed when the object doesn’t have special meaning in the AST. This is why the last one works and the second last doesn’t.

2 Likes