Expression interpolation

in doc, the following example is given:

julia> ex = :(a in $:((1, 2, 3) ) )
:(a in (1, 2, 3))

I don’t get the meaning of “expression interpolation”, as:

julia> ex2 = :(a in (1, 2, 3) )
:(a in (1, 2, 3))

julia> ex == ex2
true

why we need to do it in the way of ex, but not simply ex2? thanks.

I think the point is…everything inside :() is verbatim except for things wrapped inside $, which are evaluated beforehand. So, the following is “wrong”

t = (1,2,3)
ex = :(a in t)

but this is “right”:

t = (1,2,3)
ex = :(a in $t)

I think it is the very point the relevant section of the doc is making.

2 Likes

interpolating a variable, as in your $t example, is well understood. But I have difficulty in understanding the interpolation of an expression.

e.g.

julia> :(a - (1 + 1) )
:(a - (1 + 1))

julia> :(a - $:( (1 + 1) )  )
:(a - (1 + 1))

seems like:

  1. :( ) would quote something, i.e. prevent the thing inside being evaluated.
  2. $ would evaluate the thing after it.

so, the question is: what’s the use of $:( )??? it seems to me that the quoting and interpolation just cancels each other and do nothing??? :dizzy_face:

In that example of the docs, there is no advantage to using interpolation. A better and more useful example should probably be provided. It is indeed a useless example, since it is not a useful usecase. However, the point of interpolation is that you want to evaluate or construct a piece of code before inserting it into the expression. Therefore, a better example could be made in the docs, where the usefulness is emphasized.

… so, could we have “a better example” here? thanks. :pray:

The example could be written as

julia> ex1 = :((1, 2, 3))
:((1, 2, 3))

julia> ex = :(a in $(ex1))
:(a in (1, 2, 3))

Since you are interpolating into an expression with $, you need another expression, which is constructed using :.

Expr(:tuple, 1, 2, 3) gives the same expression as :(1, 2, 3), so one could have used

ex = :(a in $(Expr(:tuple, 1, 2, 3)))

It’s just slightly more cumbersome.

FWIW, I think that example is fine. It’s just that working with AST requires some exploration, so that chapter should be read from the begining, with the user experimenting with dump and all the examples there to understand expressions.

2 Likes

(also, moved to Usage, working with ASTs is beyond First steps)

I think it is probably important to note that interpolating a variables and expression in an expression lead to slightly different things.

julia> v = (1,2,3)
julia> dump(:(a in $v))
Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol in
    2: Symbol a
    3: Tuple{Int64,Int64,Int64}
      1: Int64 1
      2: Int64 2
      3: Int64 3
julia> dump(:(a in (1,2,3)))

Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol in
    2: Symbol a
    3: Expr
      head: Symbol tuple
      args: Array{Any}((3,))
        1: Int64 1
        2: Int64 2
        3: Int64 3

and if you don’t interpolate the expression you get.

julia> dump(:(a in :((1,2,3))))
Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol in
    2: Symbol a
    3: Expr
      head: Symbol quote
      args: Array{Any}((1,))
        1: Expr
          head: Symbol tuple
          args: Array{Any}((3,))
            1: Int64 1
            2: Int64 2
            3: Int64 3

So really what it looks like interpolating the expression does is to unwrap the inner expression and pass it as an argument. I.E. The respective difference is:

julia> Expr(:call, :in, :a, (1,2,3))
:(a in (1, 2, 3))

julia> Expr(:call, :in, :a, :((1,2,3)))
:(a in (1, 2, 3))

julia> Expr(:call, :in, :a, Expr(:quote, :(1,2,3)))
:(a in $(Expr(:quote, :((1, 2, 3)))))