4

The Scala documentation for Quasiquotes mentions this when explaining Lifting:

One can also combine lifting and unquote splicing:

 scala> val ints = List(1, 2, 3)
 scala> val f123 = q"f(..$ints)"
 f123: universe.Tree = f(1, 2, 3)

 scala> val intss = List(List(1, 2, 3), List(4, 5), List(6))
 scala> val f123456 = q"f(...$intss)"
 f123456: universe.Tree = f(1, 2, 3)(4, 5)(6)

Where specifically is the implementation of lifting vs unquote splicing in the code example?

Michael Zajac
  • 55,144
  • 7
  • 113
  • 138

1 Answers1

5

Both are happening at the same time in both examples.

Unquoting is the process of substituting a Tree somewhere into the structure of another Tree (like interpolating). In this example, ints isn't exactly a Tree, but there exists a Liftable[List[T]] that allows us to unquote a List[T] into a Tree, as if it were a Tree (ie. the Liftable tells the compiler how to transform the literal List[Int] here into a Tree so that it may be substituted).

To quote the documentation:

Unquote splicing is a way to unquote a variable number of elements.

Here, the variable number of elements would be the elements in the List we want to unquote. If we did q"f($ints)", then we would simply be unquoting ints as a single argument of f. But perhaps we want to apply repeated parameters to f instead. For that we use unquote splicing.

q"f(..$ints) // Using `..` means we get f(1, 2, 3) instead of f(List(1, 2, 3))

Again, the documentation says it best, really:

Dots near unquotee annotate degree of flattening and are also called splicing rank. ..$ expects argument to be an Iterable[Tree] and ...$ expects Iterable[Iterable[Tree]].

So lifting allows us to unquote a List[T] into the tree f(x) as if it were an Iterable[Tree], and unquote splicing allows us to unquote the variable number of elements the List[T] contained as multiple arguments for f.


Here are the different relevant combinations:

val listTree = q"scala.collection.immutable.List(1, 2, 3)"
val treeList = List(q"1", q"2", q"3")
val literalList = List(1, 2, 3)

scala> q"f($listTree)" // plain unquoting from another Tree
res6: reflect.runtime.universe.Tree = f(scala.collection.immutable.List(1, 2, 3))

scala> q"f($literalList)" // unquoting from lifting
res7: reflect.runtime.universe.Tree = f(scala.collection.immutable.List(1, 2, 3))

scala> q"f(..$treeList)" // plain unquote splicing
res8: reflect.runtime.universe.Tree = f(1, 2, 3)

scala> q"f(..$literalList)" // unquote splicing and lifting
res9: reflect.runtime.universe.Tree = f(1, 2, 3)
Michael Zajac
  • 55,144
  • 7
  • 113
  • 138
  • thanks, but i just want to say how stupid it is to name something that is ostensibly a mechanism for substitution with the prefix un-. – RoyalCanadianKiltedYaksman May 10 '15 at 23:38
  • It's not really stupid. Symbols are resolved to what they refer, if `val x = 5` then later `x` will be `5`. Quoting gives a symbol, `'x` is the symbol `x` itself. Later you can *unqoute* `'x` and place it into code where it will refer to something in that context. – muhuk May 11 '15 at 07:35