Nested expressions rules seem different when `$` involved

So normally when nesting an expression into an expression, it seems like it doesn’t matter if the latter is written as a quoted :( ___ ) or an Expr(:quote, ___ ). There’s a difference when the former is written as a quote or an Expr, but the nested expressions eval to the same inner expression.

julia> @macroexpand x + 1
:(x + 1)

julia> :( :(x+1) ) == Expr(:quote, :(x+1) )
true
julia> eval( :( :(x+1) ) )
:(x + 1)

julia> :( :(x+1) ) == :( Expr(:call, :+, :x, 1) )
false
julia> eval( :( Expr(:call, :+, :x, 1) ) )
:(x + 1)

But things seem to change when the symbol $ is involved. First, there’s no way to quote the expression Expr(:$, :x) parsed from the source code $x, which kind of makes sense because $x is a syntax error. Second, putting Expr(:$, :x) in either a quoted :( ___ ) or an Expr(:quote, ___ ) now makes a difference. The former is more like a nested expression because it evals to the inner Expr(:$, :x). The latter is almost what happens in @eval $x (and why I started on this train of thought). Third, the latter is somehow equivalent to nesting a different expression :($x) in a :( ___ ). I can’t really make sense of this.

julia> x = 3
3
julia> @macroexpand $x 
:($(Expr(:$, :x)))
julia> Expr(:$, :x) # REPL print is redundant
:($(Expr(:$, :x)))

julia> :( Expr(:$, :x) ) == Expr(:quote, Expr(:$, :x) ) # ?!
false
julia> eval( :( Expr(:$, :x) ) )
:($(Expr(:$, :x)))
julia> eval( Expr(:quote, Expr(:$, :x) ) )
3

julia> Expr(:quote, Expr(:$, :x) ) == :( :($x) ) # ?!
true

I haven’t looked into this particular example too deeply, but probably

and

are relevant. The interpolation part you encounter is the remaining edge case jeff mentions in that issue…

1 Like