Introduction to
QUASIQUOTES
By :-
SAHIL SAWHNEY
Software Consultant
KNOLDUS SOFTWARE LLP
By :-
SAHIL SAWHNEY
Software Consultant
KNOLDUS SOFTWARE LLP
Agenda
● Interpolators, a recap.
● What are quasiqoute?
● Required dependencies and imports.
● ShowRaw and showCode
● Lifting, Unlifting
● Compiling and executing ASTs
● Use case
● References
Revisiting Interpolators
➔ It is a mechanism that enable us to
sew/embed/bind WORDS in between a
processed/unprocessed string literal.
➔ We learned about s, raw and f string
interpolators
➔ Now let us uncover what quotation is which is
based on the fundamental of string
interpolators
What are Quasiquotes?
Quasiquotes are a neat notation that lets you
manipulate Scala syntax trees (AST) with
ease. Quotation syntax is in just another
usage of extensible string interpolation.
How neat are they?
val tree = q"i am { a quasiquote }"
and we have our AST.
What just happened?
The code wrapped inside q”...” is picked up and
an AST is formed from it.
NOTE →
The expression yielded by q”...” is just a tree
which is neither compiled nor executed
Justification
What according to you shall be the output for :
● scalac -Xshow-phases
(no compilation has occurred)
● Q”10 / 0”
(no execution has occurred)
Dependencies and imports.
➔ Dependencies :
"org.scala-lang" % "scala-reflect" % "2.11.8"
➔ Imports :
import scala.reflect.runtime.universe
import universe._
showRaw and showCode
➔ Understanding the pretty printers with example :
showCode : AST ––> equivalent source code
showRaw : AST ––> organization of the tree
Comparing trees
➔ ‘equalsStructure’ is used to determine if two
AST’s are structurally equal or not.
➔ Returns a true if AST are same.
q"I work at knoldus" equalsStructure q”{your
guess}”
Unqouting
➔Whenever we unquote an expression of Tree
type in a quasiquote, it will structurally
substitute that tree into the location.
➔Val a = q"class AAA"
➔Val b = q"class BBB"
➔q”$a + $b”
Splicing
➔Splicing is a way to unquote a variable number
of elements
➔One possible example can be a method call.
Discuss Example 2
Lifting
● Lifting is an extensible way to unquote custom data types
in quasiquotes.
● Int, String, Float (basic types) are all Liftable by default
● Its just
“ T –—> Tree “
val no =5
q”$no + $no”
Lifting cont..
● Liftable type is just a trait with a single abstract method that
defines a mapping of given type to tree
trait Liftable[T] {
def apply(value: T): Tree
}
● Whenever there is an implicit value of Liftable[T] available,
one can unquote T (our custom type) in quasiquotes. This
design pattern is known as a type class.
Lifting Custom Types
Demonstrating an Example of case class (most widely used
way to implement custom types in Scala) :-
case class Student(name: String, age: Int)
object Student {
implicit val lift = Liftable[Student] { stu =>
q"_root_.Student(${stu.name}, ${stu.age})"
}
}
Unlifting
● Unlifting is the reverse operation to lifting.
● It takes a tree and recovers value from it.
● Its just “ Tree –—> Option[T] “ . Why option?
val q"${left: Int} + ${right: Int}" = q"2 + 2"
Unlifting Cont..
● Unliftable type is just a trait with a single abstract method
that defines a mapping of given type to tree.
trait Unliftable[T] {
def unapply(tree: Tree): Option[T]
}
● Due to the fact that tree might not be a representation of
our data type, the return type of unapply is Option[T]
rather than just T
Unlifting Custom Types
Just add following to previous example
implicit val unliftIt = Unliftable[Student] {
case q"Student(${name: String}, ${age: Int})" =>
Student(name, age)
}
Example 3
Compiling and executing the
AST
Toolbox api serves the purpose of compiling the
AST.
Dependencies →
"org.scala-lang" % "scala-compiler" % "2.11.8"
Imports ->
import scala.reflect.runtime.currentMirror
import scala.tools.reflect.ToolBox
Compiling
The AST can be compiled using the compile
method of Toolbox with following signature :
abstract def compile(tree : U.Tree): () Any⇒
It throws an compilation error if compilation fails.
Executing
The AST can be compiled and executed using the
eval method of Toolbox with following signature :
abstract def eval(tree : U.Tree): Any
It throws an compilation error if compilation fails
and runtime error if execution fails.
Use cases
● Easy AST manipulation
● Offline code generation(AST to corrosponding
code using showCode method)
● Just in time compilation using Toolbox api
References
http://www.scala-lang.org/api/2.12.0-M4/scala-compiler
http://docs.scala-lang.org/overviews/quasiquotes/intro
https://www.youtube.com/watch?v=_c6SMsZNxms
http://www.scala-lang.org/api/2.12.0-M4/scala-compiler
http://docs.scala-lang.org/overviews/quasiquotes/intro
https://www.youtube.com/watch?v=_c6SMsZNxms
Thank You !!!

Introduction to Quasiquotes

  • 1.
    Introduction to QUASIQUOTES By :- SAHILSAWHNEY Software Consultant KNOLDUS SOFTWARE LLP By :- SAHIL SAWHNEY Software Consultant KNOLDUS SOFTWARE LLP
  • 2.
    Agenda ● Interpolators, arecap. ● What are quasiqoute? ● Required dependencies and imports. ● ShowRaw and showCode ● Lifting, Unlifting ● Compiling and executing ASTs ● Use case ● References
  • 3.
    Revisiting Interpolators ➔ Itis a mechanism that enable us to sew/embed/bind WORDS in between a processed/unprocessed string literal. ➔ We learned about s, raw and f string interpolators ➔ Now let us uncover what quotation is which is based on the fundamental of string interpolators
  • 4.
    What are Quasiquotes? Quasiquotesare a neat notation that lets you manipulate Scala syntax trees (AST) with ease. Quotation syntax is in just another usage of extensible string interpolation. How neat are they? val tree = q"i am { a quasiquote }" and we have our AST.
  • 5.
    What just happened? Thecode wrapped inside q”...” is picked up and an AST is formed from it. NOTE → The expression yielded by q”...” is just a tree which is neither compiled nor executed
  • 6.
    Justification What according toyou shall be the output for : ● scalac -Xshow-phases (no compilation has occurred) ● Q”10 / 0” (no execution has occurred)
  • 7.
    Dependencies and imports. ➔Dependencies : "org.scala-lang" % "scala-reflect" % "2.11.8" ➔ Imports : import scala.reflect.runtime.universe import universe._
  • 8.
    showRaw and showCode ➔Understanding the pretty printers with example : showCode : AST ––> equivalent source code showRaw : AST ––> organization of the tree
  • 9.
    Comparing trees ➔ ‘equalsStructure’is used to determine if two AST’s are structurally equal or not. ➔ Returns a true if AST are same. q"I work at knoldus" equalsStructure q”{your guess}”
  • 10.
    Unqouting ➔Whenever we unquotean expression of Tree type in a quasiquote, it will structurally substitute that tree into the location. ➔Val a = q"class AAA" ➔Val b = q"class BBB" ➔q”$a + $b”
  • 11.
    Splicing ➔Splicing is away to unquote a variable number of elements ➔One possible example can be a method call. Discuss Example 2
  • 12.
    Lifting ● Lifting isan extensible way to unquote custom data types in quasiquotes. ● Int, String, Float (basic types) are all Liftable by default ● Its just “ T –—> Tree “ val no =5 q”$no + $no”
  • 13.
    Lifting cont.. ● Liftabletype is just a trait with a single abstract method that defines a mapping of given type to tree trait Liftable[T] { def apply(value: T): Tree } ● Whenever there is an implicit value of Liftable[T] available, one can unquote T (our custom type) in quasiquotes. This design pattern is known as a type class.
  • 14.
    Lifting Custom Types Demonstratingan Example of case class (most widely used way to implement custom types in Scala) :- case class Student(name: String, age: Int) object Student { implicit val lift = Liftable[Student] { stu => q"_root_.Student(${stu.name}, ${stu.age})" } }
  • 15.
    Unlifting ● Unlifting isthe reverse operation to lifting. ● It takes a tree and recovers value from it. ● Its just “ Tree –—> Option[T] “ . Why option? val q"${left: Int} + ${right: Int}" = q"2 + 2"
  • 16.
    Unlifting Cont.. ● Unliftabletype is just a trait with a single abstract method that defines a mapping of given type to tree. trait Unliftable[T] { def unapply(tree: Tree): Option[T] } ● Due to the fact that tree might not be a representation of our data type, the return type of unapply is Option[T] rather than just T
  • 17.
    Unlifting Custom Types Justadd following to previous example implicit val unliftIt = Unliftable[Student] { case q"Student(${name: String}, ${age: Int})" => Student(name, age) } Example 3
  • 18.
    Compiling and executingthe AST Toolbox api serves the purpose of compiling the AST. Dependencies → "org.scala-lang" % "scala-compiler" % "2.11.8" Imports -> import scala.reflect.runtime.currentMirror import scala.tools.reflect.ToolBox
  • 19.
    Compiling The AST canbe compiled using the compile method of Toolbox with following signature : abstract def compile(tree : U.Tree): () Any⇒ It throws an compilation error if compilation fails.
  • 20.
    Executing The AST canbe compiled and executed using the eval method of Toolbox with following signature : abstract def eval(tree : U.Tree): Any It throws an compilation error if compilation fails and runtime error if execution fails.
  • 21.
    Use cases ● EasyAST manipulation ● Offline code generation(AST to corrosponding code using showCode method) ● Just in time compilation using Toolbox api
  • 22.
  • 23.