SlideShare uma empresa Scribd logo
1 de 43
Baixar para ler offline
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 1 of 22
Reflection in Scala 2.10+
Whats, Whys and Hows
Walter Cazzola
Dipartimento di Informatica
Università degli Studi di Milano
e-mail: cazzola@di.unimi.it
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 2 of 22
Computational Reflection.
General Definitions.
Computational reflection can be intuitively defined as:
cthe activity done by a SW system to represent and
manipulate its own structure and behaviord. [1]
The reflective activity is done analogously to the usual system
activity.
[1] D. Bobrow, R. G. Gabriel and J. L. White. CLOS in Context.
In OOP: the CLOS Perspective. MIT Press, 1993.
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 3 of 22
Computational Reflection.
Characterization of a Reflective System.
Structural and Behavioral Reflection
– the behavioral reflection allows the program of monitoring and
manipulating its own computation;
– the structural reflection allows the program of inspecting and al-
tering its own structure
Introspection and Intercession.
– introspection permits to observe the structure and behavior of
the application, whereas
– intercession permits to alter its structure and behavior
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 3 of 22
Computational Reflection.
Characterization of a Reflective System.
Structural and Behavioral Reflection
– the behavioral reflection allows the program of monitoring and
manipulating its own computation;
– the structural reflection allows the program of inspecting and al-
tering its own structure
Introspection and Intercession.
– introspection permits to observe the structure and behavior of
the application, whereas
– intercession permits to alter its structure and behavior
When the meta-level entities exist:
– compile-time: the causal connection is implicit, base-level and meta-
levels are merged together during a preprocessing phase;
– load-time: in this case the causal connection behaves as in the case,
reflection takes place at compile-time.
– run-time: the causal connection is explicit and must be maintained
by an entities super-parties, e.g., by the virtual machine or by the
run-time environment;
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 4 of 22
Computational Reflection.
Es. To Enrich the Behavior of a Method Call.
Each method call is logged into a file.
Hello logMeta
doLog()
doInvoke()
logMeta
hello
sayHello() invoke(sayHello)
meta
meta
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 4 of 22
Computational Reflection.
Es. To Enrich the Behavior of a Method Call.
Each method call is logged into a file.
Hello logMeta
doLog()
doInvoke()
logMeta
hello
sayHello() invoke(sayHello)
meta
meta
sayHello()
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 4 of 22
Computational Reflection.
Es. To Enrich the Behavior of a Method Call.
Each method call is logged into a file.
Hello logMeta
doLog()
doInvoke()
logMeta
hello
sayHello() invoke(sayHello)
meta
metainvoke()
sayHello()
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 4 of 22
Computational Reflection.
Es. To Enrich the Behavior of a Method Call.
Each method call is logged into a file.
¯
logFile
Hello logMeta
doLog()
doInvoke()
logMeta
hello
sayHello() invoke(sayHello)
meta
doLog()
metainvoke()
sayHello()
Method sayHello on Hello object
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 4 of 22
Computational Reflection.
Es. To Enrich the Behavior of a Method Call.
Each method call is logged into a file.
¯
logFile
console
Hello logMeta
doLog()
doInvoke()
logMeta
hello
sayHello() invoke(sayHello)
meta
doLog()
metainvoke()
sayHello()
doInvoke()
Method sayHello on Hello object
Hello World!!!
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 5 of 22
Scala Reflection.
The Java Case.
Java provides reflection via the java.lang.reflection library
– pretty good for introspection activities but
– quite limited on intercession (only behavioral manipulation)
Scala <2.10 inherits reflection from Java.
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 5 of 22
Scala Reflection.
The Java Case.
Java provides reflection via the java.lang.reflection library
– pretty good for introspection activities but
– quite limited on intercession (only behavioral manipulation)
Scala <2.10 inherits reflection from Java.
So why should we need an ad hoc implementation?
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 5 of 22
Scala Reflection.
The Java Case.
Java provides reflection via the java.lang.reflection library
– pretty good for introspection activities but
– quite limited on intercession (only behavioral manipulation)
Scala <2.10 inherits reflection from Java.
So why should we need an ad hoc implementation?
– some types are wrongly reified due to type erasure
scala> case class A[T]
scala> println(A[String].isInstanceOf[A[String]])
true
scala> println(A[String].isInstanceOf[A[Int]])
true
– the whole spectrum of types, modifiers and constructs is not cov-
ered (e.g., implicit, path dependent and abstract types)
– limited intercession, no structural reflection at all.
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 6 of 22
Reflection in Scala
Core Data Structures
Who can access to the necessary data?
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 6 of 22
Reflection in Scala
Core Data Structures
Who can access to the necessary data? The compiler.
Trees, Symbols and Types
[17:52]cazzola@surtur:~>scalac -Xshow-phases
phase name id description
---------- -- -----------
parser 1 parse source into ASTs, perform simple desugaring
namer 2 resolve names, attach symbols to named trees
typer 4 the meat and potatoes: type the trees
pickler 8 serialize symbol tables
Reflection in Scala regards
– ASTs and types
– all the information about them can be provided by the compiler
These are just few out the 30 phases the compiler performs.
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 7 of 22
Scala Reflection
-Yshow-trees
object Test {
println("Hello World!")
}
[18:05]cazzola@surtur:~>scalac -Xprint:parser -Yshow-trees helloworld.scala
[[syntax trees at end of parser]] // Scala source: helloworld.scala
PackageDef(
"<empty>"
ModuleDef(0 "Test"
Template("scala"."AnyRef" // parents
ValDef(private "_" <tpt> <empty>)
DefDef(0 "<init>" [] List(Nil) <tpt>
Block(
Apply(
super."<init>"
Nil
)()
)
)
Apply(
"println"
"Hello World!"
)
)
)
)
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 8 of 22
Scala Reflection
showRaw
scala> import scala.reflect.runtime.{universe => ru}
import scala.reflect.runtime.{universe=>ru}
scala> ru.reify{ object Test { println("Hello World!") } }
res0: reflect.runtime.universe.Expr[Unit] =
Expr[Unit]({
object Test extends AnyRef {
def <init>() = {
super.<init>();
()
};
Predef.println("Hello World!")
};
()
})
scala> ru.showRaw(res0.tree)
res1: String = Block(List(ModuleDef(Modifiers(), newTermName("Test"),
Template(List(Ident(newTypeName("AnyRef"))), emptyValDef,
List(DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(),
Block(
List(Apply(
Select(Super(This(tpnme.EMPTY), tpnme.EMPTY),
nme.CONSTRUCTOR), List())), Literal(Constant(()))
)), Apply(Select(Ident(scala.Predef),
newTermName("println")), List(Literal(Constant("Hello World!"))))
)))), Literal(Constant(())))
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 9 of 22
Reflection in Scala
Summary of the Trees
Trees are created naked by Parser.
Both definitions and references (expressed as ASTs) get their
symbols filled in by Namer (tree.symbol).
When creating symbols, Namer also creates their completers,
lazy thunks that know how to populate symbol types (symbol.info).
Typer inspects trees, uses their symbols to transform trees and
assign types to them (tree.tpe).
Shortly afterwards Pickler kicks in and serializes reachable sym-
bols along with their types into ScalaSignature annotations.
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 10 of 22
Scala Reflection
Universes & Mirrors
Universes are environments that pack together trees, symbols
and their types.
– Compiler (scala.tools.nsc.Global) is a universe.
– Reflection runtime (scala.reflect.runtime.universe) is a universe
too.
– Macro context (scala.reflect.macros.Context) holds a reference
to a universe.
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 10 of 22
Scala Reflection
Universes & Mirrors
Universes are environments that pack together trees, symbols
and their types.
– Compiler (scala.tools.nsc.Global) is a universe.
– Reflection runtime (scala.reflect.runtime.universe) is a universe
too.
– Macro context (scala.reflect.macros.Context) holds a reference
to a universe.
Mirrors abstract population of symbol tables.
Each universe can have multiple mirrors, which can share symbols
with each other within their parent universe.
– Compiler loads symbols from pickles using its own *.class parser. It
has only one mirror, the rootMirror.
– Reflective mirror uses Java reflection to load and parse ScalaSigna-
tures. Every classloader corresponds to its own mirror created
with ru.runtimeMirror(classloader).
– Macro context refers to the compiler’s symbol table.
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 11 of 22
Scala Reflection
Entry Points
Using a universe depends on your scenario.
– You can play with compiler’s universe (aka global) in REPL’s :power
mode.
– With runtime reflection you typically go through the Mirror in-
terface, e.g. scala.reflect.runtime.currentMirror, then cm.reflect
and then you can get/set fields, invoke methods, etc.
– In a macro context, you import c.universe._ and can use imported
factories to create trees and types (avoid to create symbols).
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 11 of 22
Scala Reflection
Entry Points
Using a universe depends on your scenario.
– You can play with compiler’s universe (aka global) in REPL’s :power
mode.
– With runtime reflection you typically go through the Mirror in-
terface, e.g. scala.reflect.runtime.currentMirror, then cm.reflect
and then you can get/set fields, invoke methods, etc.
– In a macro context, you import c.universe._ and can use imported
factories to create trees and types (avoid to create symbols).
All universe artifacts are path-dependent on their universe.
scala> import scala.reflect.runtime.{universe => ru}
import scala.reflect.runtime.{universe=>ru}
scala> ru.reify(2.toString)
res1: reflect.runtime.universe.Expr[String] = Expr[String](2.toString())
With runtime reflection, there is only one universe.
With macros it is more complicated. To pass artifacts around is
necessary to piggyback the universe as well.
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 12 of 22
Scala Reflection
Inspect Members
scala> import scala.reflect.runtime.{universe => ru}
import scala.reflect.runtime.{universe=>ru}
scala> trait X { def foo: String }
defined trait X
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 12 of 22
Scala Reflection
Inspect Members
scala> import scala.reflect.runtime.{universe => ru}
import scala.reflect.runtime.{universe=>ru}
scala> trait X { def foo: String }
defined trait X
scala> ru.typeOf[X]
res0: reflect.runtime.universe.Type = X
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 12 of 22
Scala Reflection
Inspect Members
scala> import scala.reflect.runtime.{universe => ru}
import scala.reflect.runtime.{universe=>ru}
scala> trait X { def foo: String }
defined trait X
scala> ru.typeOf[X]
res0: reflect.runtime.universe.Type = X
scala> res0.members
res1: reflect.runtime.universe.MemberScope =
Scopes(method $asInstanceOf, method $isInstanceOf, method synchronized,
method ##, method !=, method ==, method ne, method eq, constructor Object,
method notifyAll, method notify, method clone, method getClass,
method hashCode, method toString, method equals, method wait,
method finalize, method asInstanceOf, method isInstanceOf, method !=,
method ==, method foo)
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 13 of 22
Scala Reflection
Analyze and Invoke Members
Get the type, the constructor and its parameters
scala> case class Person(name: String, age: Int)
defined class Person
scala> val personType = typeOf[Person]
personType: reflect.runtime.universe.Type = Person
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 13 of 22
Scala Reflection
Analyze and Invoke Members
Get the type, the constructor and its parameters
scala> case class Person(name: String, age: Int)
defined class Person
scala> val personType = typeOf[Person]
personType: reflect.runtime.universe.Type = Person
scala> val ctor = personType.member(nme.CONSTRUCTOR)
ctor: reflect.runtime.universe.Symbol = constructor Person
scala> val args = ctor.asMethod.paramss.head map {p => (p.name.decoded, p.typeSignature)}
args: List[(String, reflect.runtime.universe.Type)] = List((name,String), (age,scala.Int))
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 13 of 22
Scala Reflection
Analyze and Invoke Members
Get the type, the constructor and its parameters
scala> case class Person(name: String, age: Int)
defined class Person
scala> val personType = typeOf[Person]
personType: reflect.runtime.universe.Type = Person
scala> val ctor = personType.member(nme.CONSTRUCTOR)
ctor: reflect.runtime.universe.Symbol = constructor Person
scala> val args = ctor.asMethod.paramss.head map {p => (p.name.decoded, p.typeSignature)}
args: List[(String, reflect.runtime.universe.Type)] = List((name,String), (age,scala.Int))
Create a new instance (via the mirror)
scala> val classMirror = currentMirror.reflectClass(personType.typeSymbol.asClass)
classMirror: reflect.runtime.universe.ClassMirror = class mirror for Person
scala> val ctor = personType.declaration(nme.CONSTRUCTOR).asMethod
ctor: reflect.runtime.universe.MethodSymbol = constructor Person
scala> classMirror.reflectConstructor(ctor).apply("Joe", 73)
res1: Any = Person(Joe,73)
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 14 of 22
Scala Reflection
Defeat Type Erasure
The compiler implements the type erasure
scala> case class A[T]
scala> println(A[String].isInstanceOf[A[String]])
true
scala> println(A[String].isInstanceOf[A[Int]])
true
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 14 of 22
Scala Reflection
Defeat Type Erasure
The compiler implements the type erasure
scala> case class A[T]
scala> println(A[String].isInstanceOf[A[String]])
true
scala> println(A[String].isInstanceOf[A[Int]])
true
Solution: to pass through the reflective TypeTag
scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._
scala> case class B[T: TypeTag] { val tpe = typeOf[T] }
defined class B
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 14 of 22
Scala Reflection
Defeat Type Erasure
The compiler implements the type erasure
scala> case class A[T]
scala> println(A[String].isInstanceOf[A[String]])
true
scala> println(A[String].isInstanceOf[A[Int]])
true
Solution: to pass through the reflective TypeTag
scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._
scala> case class B[T: TypeTag] { val tpe = typeOf[T] }
defined class B
scala> println(B[String].tpe == typeOf[String])
true
scala> println(B[String].tpe == typeOf[Int])
false
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 14 of 22
Scala Reflection
Defeat Type Erasure
The compiler implements the type erasure
scala> case class A[T]
scala> println(A[String].isInstanceOf[A[String]])
true
scala> println(A[String].isInstanceOf[A[Int]])
true
Solution: to pass through the reflective TypeTag
scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._
scala> case class B[T: TypeTag] { val tpe = typeOf[T] }
defined class B
scala> println(B[String].tpe == typeOf[String])
true
scala> println(B[String].tpe == typeOf[Int])
false
scala> println(B[List[String]].tpe == typeOf[List[String]])
true
scala> println(B[List[String]].tpe == typeOf[List[Int]])
false
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 15 of 22
Scala Reflection
Compilation at Run-Time
scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._
scala> import scala.tools.reflect.ToolBox
import scala.tools.reflect.ToolBox
scala> val tree = Apply(
Select(Literal(Constant(40)), newTermName("$plus")), List(Literal(Constant(2))))
tree: reflect.runtime.universe.Apply = 40.$plus(2)
scala> val cm = scala.reflect.runtime.universe.runtimeMirror(getClass.getClassLoader)
cm: reflect.runtime.universe.Mirror = JavaMirror with ...
scala> println(cm.mkToolBox().eval(tree))
42
Toolbox is a full-fledged compiler.
– Unlike the regular compiler, it uses Java reflection encapsulated in
the provided mirror to populate its symbol table.
– Toolbox wraps the input AST, sets its phase to Namer (skipping
Parser) and performs the compilation into an in-memory directory.
– After the compilation is finished, toolbox fires up a classloader that
loads and lauches the code.
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 16 of 22
Scala Reflection
Compile-Time Reflection or Structural Reflection
Macro
It is a pattern or a rule that specifies how a given input se-
quence should be mapped into another.
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 16 of 22
Scala Reflection
Compile-Time Reflection or Structural Reflection
Macro
It is a pattern or a rule that specifies how a given input se-
quence should be mapped into another.
. . . but what is a macro, really?
A regular scala function that transforms an AST into another
AST and it is called by the compiler.
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 16 of 22
Scala Reflection
Compile-Time Reflection or Structural Reflection
Macro
It is a pattern or a rule that specifies how a given input se-
quence should be mapped into another.
. . . but what is a macro, really?
A regular scala function that transforms an AST into another
AST and it is called by the compiler.
E.g.,
if (1 ==1) { true } else { false }
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 16 of 22
Scala Reflection
Compile-Time Reflection or Structural Reflection
Macro
It is a pattern or a rule that specifies how a given input se-
quence should be mapped into another.
. . . but what is a macro, really?
A regular scala function that transforms an AST into another
AST and it is called by the compiler.
E.g.,
if (1 ==1) { true } else { false }
if (1.$eq$eq(1)) { true } else { false }
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 17 of 22
Scala Reflection
Abstract Syntax Tree (AST)
if (1.$eq$eq(1)) {true} else {false}
If
Apply
Select
Literal
1
"$eq$eq"
List
Literal
1
Literal
true
Literal
false
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 18 of 22
Scala Reflection
Applications of the Macros
Macros permits to transform an AST into a new AST at com-
pile time.
. . . but what we can do wth that?
E.g.,
– zero-overhead assertions, logging or bounds checking;
– static loops unroll or other kind of optimization; or
– static DSL transformation
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 19 of 22
Scala Reflection
Macros in Action
import scala.language.experimental.macros
import scala.reflect.macros.Context
import scala.collection.mutable.{ListBuffer, Stack}
object Macros {
def printf(format: String, params: Any*): Unit = macro printf_impl
def printf_impl(c:Context)(format:c.Expr[String], params:c.Expr[Any]*):c.Expr[Unit]={
import c.universe._
val Literal(Constant(s_format: String)) = format.tree
val evals = ListBuffer[ValDef]()
def precompute(value: Tree, tpe: Type): Ident = {
val freshName = newTermName(c.fresh("eval$"))
evals += ValDef(Modifiers(), freshName, TypeTree(tpe), value)
Ident(freshName)
}
val paramsStack = Stack[Tree]((params map (_.tree)): _*)
val refs = s_format.split("(?<=%[w%])|(?=%[w%])") map {
case "%d" => precompute(paramsStack.pop, typeOf[Int])
case "%s" => precompute(paramsStack.pop, typeOf[String])
case "%%" => Literal(Constant("%"))
case part => Literal(Constant(part))
}
val stats = evals ++ refs.map(ref => reify(print(c.Expr[Any](ref).splice)).tree)
c.Expr[Unit](Block(stats.toList, Literal(Constant(()))))
}
}
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 20 of 22
Scala Reflection
Macros in Action
object Test extends App {
import Macros._
printf("hello %s!", "world")
}
[22:18]cazzola@surtur:~>scalac Macros.scala
[22:19]cazzola@surtur:~>scalac Test.scala
[22:20]cazzola@surtur:~>scala Test
hello world!
Note that,
– macros must be compiled separately from where they should used,
i.e., no recursive macros are possible;
– macros work on compile time information, i.e., they reify, manipulate
and return an AST.
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 21 of 22
Scala Reflection
Conclusions
In Scala 2.10+ you can have all the information about your pro-
gram that the compiler has (well, almost).
– this includes trees, symbols and types and more.
– you can reflect at run-time (scala.reflect.runtime.universe) or at
compile-time (macros).
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 21 of 22
Scala Reflection
Conclusions
In Scala 2.10+ you can have all the information about your pro-
gram that the compiler has (well, almost).
– this includes trees, symbols and types and more.
– you can reflect at run-time (scala.reflect.runtime.universe) or at
compile-time (macros).
But (Devil’s Advocate) . . .
– we are still far from C++ Template Programming, e.g., no factorial
at compile time.
– Java reflection, even if limited, is easier to use.
Reflection in
Scala 2.10+
Walter Cazzola
Reflection
introduction
properties
example
Scala Reflection
trees
universes
examples
Macros
References
Slide 22 of 22
References
Martin Odersky.
Reflection and Compilers.
Keynote at Lang.NEXT, April 2012.
Eugene Burmako.
Macros.
Scala 2.10 documentation, École Polytechnique Fédérale de Lausanne,
2013.
Heather Miller, Eugene Burmako, and Philipp Haller.
Scala Reflection 2.10.
Scala 2.10 documentation, École Polytechnique Fédérale de Lausanne,
2013.

Mais conteúdo relacionado

Semelhante a Reflection in Scala Whats, Whys and Hows - Walter Cazzola (Dipartimento di Informatica - Università degli Studi di Milano)

Martin Odersky - Evolution of Scala
Martin Odersky - Evolution of ScalaMartin Odersky - Evolution of Scala
Martin Odersky - Evolution of Scala
Scala Italy
 
Why Doesn't Java Has Instant Turnaround - Con-FESS 2012
Why Doesn't Java Has Instant Turnaround - Con-FESS 2012Why Doesn't Java Has Instant Turnaround - Con-FESS 2012
Why Doesn't Java Has Instant Turnaround - Con-FESS 2012
Anton Arhipov
 
Rapid java application development @ JUG.ru 25.02.2012
Rapid java application development @ JUG.ru 25.02.2012Rapid java application development @ JUG.ru 25.02.2012
Rapid java application development @ JUG.ru 25.02.2012
Anton Arhipov
 
Reflection in java
Reflection in javaReflection in java
Reflection in java
upen.rockin
 

Semelhante a Reflection in Scala Whats, Whys and Hows - Walter Cazzola (Dipartimento di Informatica - Università degli Studi di Milano) (20)

Metaprogramming in Scala 2.10, Eugene Burmako,
Metaprogramming  in Scala 2.10, Eugene Burmako, Metaprogramming  in Scala 2.10, Eugene Burmako,
Metaprogramming in Scala 2.10, Eugene Burmako,
 
The Scala Refactoring Library: Problems and Perspectives
The Scala Refactoring Library: Problems and PerspectivesThe Scala Refactoring Library: Problems and Perspectives
The Scala Refactoring Library: Problems and Perspectives
 
Devoxx
DevoxxDevoxx
Devoxx
 
scala.reflect, Eugene Burmako
scala.reflect, Eugene Burmakoscala.reflect, Eugene Burmako
scala.reflect, Eugene Burmako
 
Евгений Бурмако «scala.reflect»
Евгений Бурмако «scala.reflect»Евгений Бурмако «scala.reflect»
Евгений Бурмако «scala.reflect»
 
Scala Days San Francisco
Scala Days San FranciscoScala Days San Francisco
Scala Days San Francisco
 
Scala lens: An introduction
Scala lens: An introductionScala lens: An introduction
Scala lens: An introduction
 
Project kepler compile time metaprogramming for scala
Project kepler compile time metaprogramming for scalaProject kepler compile time metaprogramming for scala
Project kepler compile time metaprogramming for scala
 
Martin Odersky - Evolution of Scala
Martin Odersky - Evolution of ScalaMartin Odersky - Evolution of Scala
Martin Odersky - Evolution of Scala
 
20140908 spark sql & catalyst
20140908 spark sql & catalyst20140908 spark sql & catalyst
20140908 spark sql & catalyst
 
Why Doesn't Java Has Instant Turnaround - Con-FESS 2012
Why Doesn't Java Has Instant Turnaround - Con-FESS 2012Why Doesn't Java Has Instant Turnaround - Con-FESS 2012
Why Doesn't Java Has Instant Turnaround - Con-FESS 2012
 
Refactoring to Scala DSLs and LiftOff 2009 Recap
Refactoring to Scala DSLs and LiftOff 2009 RecapRefactoring to Scala DSLs and LiftOff 2009 Recap
Refactoring to Scala DSLs and LiftOff 2009 Recap
 
Stepping Up : A Brief Intro to Scala
Stepping Up : A Brief Intro to ScalaStepping Up : A Brief Intro to Scala
Stepping Up : A Brief Intro to Scala
 
Rapid java application development @ JUG.ru 25.02.2012
Rapid java application development @ JUG.ru 25.02.2012Rapid java application development @ JUG.ru 25.02.2012
Rapid java application development @ JUG.ru 25.02.2012
 
Scala active record
Scala active recordScala active record
Scala active record
 
Martin Odersky: What's next for Scala
Martin Odersky: What's next for ScalaMartin Odersky: What's next for Scala
Martin Odersky: What's next for Scala
 
Scalaマクロ入門 bizr20170217
Scalaマクロ入門 bizr20170217 Scalaマクロ入門 bizr20170217
Scalaマクロ入門 bizr20170217
 
How Scala promotes TDD
How Scala promotes TDDHow Scala promotes TDD
How Scala promotes TDD
 
Scala - The Simple Parts, SFScala presentation
Scala - The Simple Parts, SFScala presentationScala - The Simple Parts, SFScala presentation
Scala - The Simple Parts, SFScala presentation
 
Reflection in java
Reflection in javaReflection in java
Reflection in java
 

Mais de Scala Italy

Mais de Scala Italy (12)

Alessandro Abbruzzetti - Kernal64
Alessandro Abbruzzetti - Kernal64Alessandro Abbruzzetti - Kernal64
Alessandro Abbruzzetti - Kernal64
 
Alberto Paro - Hands on Scala.js
Alberto Paro - Hands on Scala.jsAlberto Paro - Hands on Scala.js
Alberto Paro - Hands on Scala.js
 
Andrea Lattuada, Gabriele Petronella - Building startups on Scala
Andrea Lattuada, Gabriele Petronella - Building startups on ScalaAndrea Lattuada, Gabriele Petronella - Building startups on Scala
Andrea Lattuada, Gabriele Petronella - Building startups on Scala
 
Stefano Rocco, Roberto Bentivoglio - Scala in increasingly demanding environm...
Stefano Rocco, Roberto Bentivoglio - Scala in increasingly demanding environm...Stefano Rocco, Roberto Bentivoglio - Scala in increasingly demanding environm...
Stefano Rocco, Roberto Bentivoglio - Scala in increasingly demanding environm...
 
Federico Feroldi - Scala microservices
Federico Feroldi - Scala microservicesFederico Feroldi - Scala microservices
Federico Feroldi - Scala microservices
 
Daniela Sfregola - Intro to Akka
Daniela Sfregola - Intro to AkkaDaniela Sfregola - Intro to Akka
Daniela Sfregola - Intro to Akka
 
Mirco Dotta - Akka Streams
Mirco Dotta - Akka StreamsMirco Dotta - Akka Streams
Mirco Dotta - Akka Streams
 
Phil Calçado - Your microservice as a function
Phil Calçado - Your microservice as a functionPhil Calçado - Your microservice as a function
Phil Calçado - Your microservice as a function
 
Scalatra - Massimiliano Dessì (Energeya)
Scalatra - Massimiliano Dessì (Energeya)Scalatra - Massimiliano Dessì (Energeya)
Scalatra - Massimiliano Dessì (Energeya)
 
Scala: the language of languages - Mario Fusco (Red Hat)
Scala: the language of languages - Mario Fusco (Red Hat)Scala: the language of languages - Mario Fusco (Red Hat)
Scala: the language of languages - Mario Fusco (Red Hat)
 
Simplifying development-short - Mirco Dotta (Typesafe)
Simplifying development-short - Mirco Dotta (Typesafe)Simplifying development-short - Mirco Dotta (Typesafe)
Simplifying development-short - Mirco Dotta (Typesafe)
 
Scala in pratica - Stefano Rocco (MoneyFarm)
Scala in pratica - Stefano Rocco (MoneyFarm)Scala in pratica - Stefano Rocco (MoneyFarm)
Scala in pratica - Stefano Rocco (MoneyFarm)
 

Último

Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Último (20)

Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 

Reflection in Scala Whats, Whys and Hows - Walter Cazzola (Dipartimento di Informatica - Università degli Studi di Milano)

  • 1. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 1 of 22 Reflection in Scala 2.10+ Whats, Whys and Hows Walter Cazzola Dipartimento di Informatica Università degli Studi di Milano e-mail: cazzola@di.unimi.it
  • 2. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 2 of 22 Computational Reflection. General Definitions. Computational reflection can be intuitively defined as: cthe activity done by a SW system to represent and manipulate its own structure and behaviord. [1] The reflective activity is done analogously to the usual system activity. [1] D. Bobrow, R. G. Gabriel and J. L. White. CLOS in Context. In OOP: the CLOS Perspective. MIT Press, 1993.
  • 3. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 3 of 22 Computational Reflection. Characterization of a Reflective System. Structural and Behavioral Reflection – the behavioral reflection allows the program of monitoring and manipulating its own computation; – the structural reflection allows the program of inspecting and al- tering its own structure Introspection and Intercession. – introspection permits to observe the structure and behavior of the application, whereas – intercession permits to alter its structure and behavior
  • 4. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 3 of 22 Computational Reflection. Characterization of a Reflective System. Structural and Behavioral Reflection – the behavioral reflection allows the program of monitoring and manipulating its own computation; – the structural reflection allows the program of inspecting and al- tering its own structure Introspection and Intercession. – introspection permits to observe the structure and behavior of the application, whereas – intercession permits to alter its structure and behavior When the meta-level entities exist: – compile-time: the causal connection is implicit, base-level and meta- levels are merged together during a preprocessing phase; – load-time: in this case the causal connection behaves as in the case, reflection takes place at compile-time. – run-time: the causal connection is explicit and must be maintained by an entities super-parties, e.g., by the virtual machine or by the run-time environment;
  • 5. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 4 of 22 Computational Reflection. Es. To Enrich the Behavior of a Method Call. Each method call is logged into a file. Hello logMeta doLog() doInvoke() logMeta hello sayHello() invoke(sayHello) meta meta
  • 6. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 4 of 22 Computational Reflection. Es. To Enrich the Behavior of a Method Call. Each method call is logged into a file. Hello logMeta doLog() doInvoke() logMeta hello sayHello() invoke(sayHello) meta meta sayHello()
  • 7. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 4 of 22 Computational Reflection. Es. To Enrich the Behavior of a Method Call. Each method call is logged into a file. Hello logMeta doLog() doInvoke() logMeta hello sayHello() invoke(sayHello) meta metainvoke() sayHello()
  • 8. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 4 of 22 Computational Reflection. Es. To Enrich the Behavior of a Method Call. Each method call is logged into a file. ¯ logFile Hello logMeta doLog() doInvoke() logMeta hello sayHello() invoke(sayHello) meta doLog() metainvoke() sayHello() Method sayHello on Hello object
  • 9. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 4 of 22 Computational Reflection. Es. To Enrich the Behavior of a Method Call. Each method call is logged into a file. ¯ logFile console Hello logMeta doLog() doInvoke() logMeta hello sayHello() invoke(sayHello) meta doLog() metainvoke() sayHello() doInvoke() Method sayHello on Hello object Hello World!!!
  • 10. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 5 of 22 Scala Reflection. The Java Case. Java provides reflection via the java.lang.reflection library – pretty good for introspection activities but – quite limited on intercession (only behavioral manipulation) Scala <2.10 inherits reflection from Java.
  • 11. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 5 of 22 Scala Reflection. The Java Case. Java provides reflection via the java.lang.reflection library – pretty good for introspection activities but – quite limited on intercession (only behavioral manipulation) Scala <2.10 inherits reflection from Java. So why should we need an ad hoc implementation?
  • 12. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 5 of 22 Scala Reflection. The Java Case. Java provides reflection via the java.lang.reflection library – pretty good for introspection activities but – quite limited on intercession (only behavioral manipulation) Scala <2.10 inherits reflection from Java. So why should we need an ad hoc implementation? – some types are wrongly reified due to type erasure scala> case class A[T] scala> println(A[String].isInstanceOf[A[String]]) true scala> println(A[String].isInstanceOf[A[Int]]) true – the whole spectrum of types, modifiers and constructs is not cov- ered (e.g., implicit, path dependent and abstract types) – limited intercession, no structural reflection at all.
  • 13. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 6 of 22 Reflection in Scala Core Data Structures Who can access to the necessary data?
  • 14. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 6 of 22 Reflection in Scala Core Data Structures Who can access to the necessary data? The compiler. Trees, Symbols and Types [17:52]cazzola@surtur:~>scalac -Xshow-phases phase name id description ---------- -- ----------- parser 1 parse source into ASTs, perform simple desugaring namer 2 resolve names, attach symbols to named trees typer 4 the meat and potatoes: type the trees pickler 8 serialize symbol tables Reflection in Scala regards – ASTs and types – all the information about them can be provided by the compiler These are just few out the 30 phases the compiler performs.
  • 15. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 7 of 22 Scala Reflection -Yshow-trees object Test { println("Hello World!") } [18:05]cazzola@surtur:~>scalac -Xprint:parser -Yshow-trees helloworld.scala [[syntax trees at end of parser]] // Scala source: helloworld.scala PackageDef( "<empty>" ModuleDef(0 "Test" Template("scala"."AnyRef" // parents ValDef(private "_" <tpt> <empty>) DefDef(0 "<init>" [] List(Nil) <tpt> Block( Apply( super."<init>" Nil )() ) ) Apply( "println" "Hello World!" ) ) ) )
  • 16. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 8 of 22 Scala Reflection showRaw scala> import scala.reflect.runtime.{universe => ru} import scala.reflect.runtime.{universe=>ru} scala> ru.reify{ object Test { println("Hello World!") } } res0: reflect.runtime.universe.Expr[Unit] = Expr[Unit]({ object Test extends AnyRef { def <init>() = { super.<init>(); () }; Predef.println("Hello World!") }; () }) scala> ru.showRaw(res0.tree) res1: String = Block(List(ModuleDef(Modifiers(), newTermName("Test"), Template(List(Ident(newTypeName("AnyRef"))), emptyValDef, List(DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(), Block( List(Apply( Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), Literal(Constant(())) )), Apply(Select(Ident(scala.Predef), newTermName("println")), List(Literal(Constant("Hello World!")))) )))), Literal(Constant(())))
  • 17. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 9 of 22 Reflection in Scala Summary of the Trees Trees are created naked by Parser. Both definitions and references (expressed as ASTs) get their symbols filled in by Namer (tree.symbol). When creating symbols, Namer also creates their completers, lazy thunks that know how to populate symbol types (symbol.info). Typer inspects trees, uses their symbols to transform trees and assign types to them (tree.tpe). Shortly afterwards Pickler kicks in and serializes reachable sym- bols along with their types into ScalaSignature annotations.
  • 18. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 10 of 22 Scala Reflection Universes & Mirrors Universes are environments that pack together trees, symbols and their types. – Compiler (scala.tools.nsc.Global) is a universe. – Reflection runtime (scala.reflect.runtime.universe) is a universe too. – Macro context (scala.reflect.macros.Context) holds a reference to a universe.
  • 19. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 10 of 22 Scala Reflection Universes & Mirrors Universes are environments that pack together trees, symbols and their types. – Compiler (scala.tools.nsc.Global) is a universe. – Reflection runtime (scala.reflect.runtime.universe) is a universe too. – Macro context (scala.reflect.macros.Context) holds a reference to a universe. Mirrors abstract population of symbol tables. Each universe can have multiple mirrors, which can share symbols with each other within their parent universe. – Compiler loads symbols from pickles using its own *.class parser. It has only one mirror, the rootMirror. – Reflective mirror uses Java reflection to load and parse ScalaSigna- tures. Every classloader corresponds to its own mirror created with ru.runtimeMirror(classloader). – Macro context refers to the compiler’s symbol table.
  • 20. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 11 of 22 Scala Reflection Entry Points Using a universe depends on your scenario. – You can play with compiler’s universe (aka global) in REPL’s :power mode. – With runtime reflection you typically go through the Mirror in- terface, e.g. scala.reflect.runtime.currentMirror, then cm.reflect and then you can get/set fields, invoke methods, etc. – In a macro context, you import c.universe._ and can use imported factories to create trees and types (avoid to create symbols).
  • 21. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 11 of 22 Scala Reflection Entry Points Using a universe depends on your scenario. – You can play with compiler’s universe (aka global) in REPL’s :power mode. – With runtime reflection you typically go through the Mirror in- terface, e.g. scala.reflect.runtime.currentMirror, then cm.reflect and then you can get/set fields, invoke methods, etc. – In a macro context, you import c.universe._ and can use imported factories to create trees and types (avoid to create symbols). All universe artifacts are path-dependent on their universe. scala> import scala.reflect.runtime.{universe => ru} import scala.reflect.runtime.{universe=>ru} scala> ru.reify(2.toString) res1: reflect.runtime.universe.Expr[String] = Expr[String](2.toString()) With runtime reflection, there is only one universe. With macros it is more complicated. To pass artifacts around is necessary to piggyback the universe as well.
  • 22. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 12 of 22 Scala Reflection Inspect Members scala> import scala.reflect.runtime.{universe => ru} import scala.reflect.runtime.{universe=>ru} scala> trait X { def foo: String } defined trait X
  • 23. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 12 of 22 Scala Reflection Inspect Members scala> import scala.reflect.runtime.{universe => ru} import scala.reflect.runtime.{universe=>ru} scala> trait X { def foo: String } defined trait X scala> ru.typeOf[X] res0: reflect.runtime.universe.Type = X
  • 24. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 12 of 22 Scala Reflection Inspect Members scala> import scala.reflect.runtime.{universe => ru} import scala.reflect.runtime.{universe=>ru} scala> trait X { def foo: String } defined trait X scala> ru.typeOf[X] res0: reflect.runtime.universe.Type = X scala> res0.members res1: reflect.runtime.universe.MemberScope = Scopes(method $asInstanceOf, method $isInstanceOf, method synchronized, method ##, method !=, method ==, method ne, method eq, constructor Object, method notifyAll, method notify, method clone, method getClass, method hashCode, method toString, method equals, method wait, method finalize, method asInstanceOf, method isInstanceOf, method !=, method ==, method foo)
  • 25. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 13 of 22 Scala Reflection Analyze and Invoke Members Get the type, the constructor and its parameters scala> case class Person(name: String, age: Int) defined class Person scala> val personType = typeOf[Person] personType: reflect.runtime.universe.Type = Person
  • 26. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 13 of 22 Scala Reflection Analyze and Invoke Members Get the type, the constructor and its parameters scala> case class Person(name: String, age: Int) defined class Person scala> val personType = typeOf[Person] personType: reflect.runtime.universe.Type = Person scala> val ctor = personType.member(nme.CONSTRUCTOR) ctor: reflect.runtime.universe.Symbol = constructor Person scala> val args = ctor.asMethod.paramss.head map {p => (p.name.decoded, p.typeSignature)} args: List[(String, reflect.runtime.universe.Type)] = List((name,String), (age,scala.Int))
  • 27. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 13 of 22 Scala Reflection Analyze and Invoke Members Get the type, the constructor and its parameters scala> case class Person(name: String, age: Int) defined class Person scala> val personType = typeOf[Person] personType: reflect.runtime.universe.Type = Person scala> val ctor = personType.member(nme.CONSTRUCTOR) ctor: reflect.runtime.universe.Symbol = constructor Person scala> val args = ctor.asMethod.paramss.head map {p => (p.name.decoded, p.typeSignature)} args: List[(String, reflect.runtime.universe.Type)] = List((name,String), (age,scala.Int)) Create a new instance (via the mirror) scala> val classMirror = currentMirror.reflectClass(personType.typeSymbol.asClass) classMirror: reflect.runtime.universe.ClassMirror = class mirror for Person scala> val ctor = personType.declaration(nme.CONSTRUCTOR).asMethod ctor: reflect.runtime.universe.MethodSymbol = constructor Person scala> classMirror.reflectConstructor(ctor).apply("Joe", 73) res1: Any = Person(Joe,73)
  • 28. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 14 of 22 Scala Reflection Defeat Type Erasure The compiler implements the type erasure scala> case class A[T] scala> println(A[String].isInstanceOf[A[String]]) true scala> println(A[String].isInstanceOf[A[Int]]) true
  • 29. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 14 of 22 Scala Reflection Defeat Type Erasure The compiler implements the type erasure scala> case class A[T] scala> println(A[String].isInstanceOf[A[String]]) true scala> println(A[String].isInstanceOf[A[Int]]) true Solution: to pass through the reflective TypeTag scala> import scala.reflect.runtime.universe._ import scala.reflect.runtime.universe._ scala> case class B[T: TypeTag] { val tpe = typeOf[T] } defined class B
  • 30. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 14 of 22 Scala Reflection Defeat Type Erasure The compiler implements the type erasure scala> case class A[T] scala> println(A[String].isInstanceOf[A[String]]) true scala> println(A[String].isInstanceOf[A[Int]]) true Solution: to pass through the reflective TypeTag scala> import scala.reflect.runtime.universe._ import scala.reflect.runtime.universe._ scala> case class B[T: TypeTag] { val tpe = typeOf[T] } defined class B scala> println(B[String].tpe == typeOf[String]) true scala> println(B[String].tpe == typeOf[Int]) false
  • 31. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 14 of 22 Scala Reflection Defeat Type Erasure The compiler implements the type erasure scala> case class A[T] scala> println(A[String].isInstanceOf[A[String]]) true scala> println(A[String].isInstanceOf[A[Int]]) true Solution: to pass through the reflective TypeTag scala> import scala.reflect.runtime.universe._ import scala.reflect.runtime.universe._ scala> case class B[T: TypeTag] { val tpe = typeOf[T] } defined class B scala> println(B[String].tpe == typeOf[String]) true scala> println(B[String].tpe == typeOf[Int]) false scala> println(B[List[String]].tpe == typeOf[List[String]]) true scala> println(B[List[String]].tpe == typeOf[List[Int]]) false
  • 32. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 15 of 22 Scala Reflection Compilation at Run-Time scala> import scala.reflect.runtime.universe._ import scala.reflect.runtime.universe._ scala> import scala.tools.reflect.ToolBox import scala.tools.reflect.ToolBox scala> val tree = Apply( Select(Literal(Constant(40)), newTermName("$plus")), List(Literal(Constant(2)))) tree: reflect.runtime.universe.Apply = 40.$plus(2) scala> val cm = scala.reflect.runtime.universe.runtimeMirror(getClass.getClassLoader) cm: reflect.runtime.universe.Mirror = JavaMirror with ... scala> println(cm.mkToolBox().eval(tree)) 42 Toolbox is a full-fledged compiler. – Unlike the regular compiler, it uses Java reflection encapsulated in the provided mirror to populate its symbol table. – Toolbox wraps the input AST, sets its phase to Namer (skipping Parser) and performs the compilation into an in-memory directory. – After the compilation is finished, toolbox fires up a classloader that loads and lauches the code.
  • 33. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 16 of 22 Scala Reflection Compile-Time Reflection or Structural Reflection Macro It is a pattern or a rule that specifies how a given input se- quence should be mapped into another.
  • 34. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 16 of 22 Scala Reflection Compile-Time Reflection or Structural Reflection Macro It is a pattern or a rule that specifies how a given input se- quence should be mapped into another. . . . but what is a macro, really? A regular scala function that transforms an AST into another AST and it is called by the compiler.
  • 35. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 16 of 22 Scala Reflection Compile-Time Reflection or Structural Reflection Macro It is a pattern or a rule that specifies how a given input se- quence should be mapped into another. . . . but what is a macro, really? A regular scala function that transforms an AST into another AST and it is called by the compiler. E.g., if (1 ==1) { true } else { false }
  • 36. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 16 of 22 Scala Reflection Compile-Time Reflection or Structural Reflection Macro It is a pattern or a rule that specifies how a given input se- quence should be mapped into another. . . . but what is a macro, really? A regular scala function that transforms an AST into another AST and it is called by the compiler. E.g., if (1 ==1) { true } else { false } if (1.$eq$eq(1)) { true } else { false }
  • 37. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 17 of 22 Scala Reflection Abstract Syntax Tree (AST) if (1.$eq$eq(1)) {true} else {false} If Apply Select Literal 1 "$eq$eq" List Literal 1 Literal true Literal false
  • 38. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 18 of 22 Scala Reflection Applications of the Macros Macros permits to transform an AST into a new AST at com- pile time. . . . but what we can do wth that? E.g., – zero-overhead assertions, logging or bounds checking; – static loops unroll or other kind of optimization; or – static DSL transformation
  • 39. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 19 of 22 Scala Reflection Macros in Action import scala.language.experimental.macros import scala.reflect.macros.Context import scala.collection.mutable.{ListBuffer, Stack} object Macros { def printf(format: String, params: Any*): Unit = macro printf_impl def printf_impl(c:Context)(format:c.Expr[String], params:c.Expr[Any]*):c.Expr[Unit]={ import c.universe._ val Literal(Constant(s_format: String)) = format.tree val evals = ListBuffer[ValDef]() def precompute(value: Tree, tpe: Type): Ident = { val freshName = newTermName(c.fresh("eval$")) evals += ValDef(Modifiers(), freshName, TypeTree(tpe), value) Ident(freshName) } val paramsStack = Stack[Tree]((params map (_.tree)): _*) val refs = s_format.split("(?<=%[w%])|(?=%[w%])") map { case "%d" => precompute(paramsStack.pop, typeOf[Int]) case "%s" => precompute(paramsStack.pop, typeOf[String]) case "%%" => Literal(Constant("%")) case part => Literal(Constant(part)) } val stats = evals ++ refs.map(ref => reify(print(c.Expr[Any](ref).splice)).tree) c.Expr[Unit](Block(stats.toList, Literal(Constant(())))) } }
  • 40. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 20 of 22 Scala Reflection Macros in Action object Test extends App { import Macros._ printf("hello %s!", "world") } [22:18]cazzola@surtur:~>scalac Macros.scala [22:19]cazzola@surtur:~>scalac Test.scala [22:20]cazzola@surtur:~>scala Test hello world! Note that, – macros must be compiled separately from where they should used, i.e., no recursive macros are possible; – macros work on compile time information, i.e., they reify, manipulate and return an AST.
  • 41. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 21 of 22 Scala Reflection Conclusions In Scala 2.10+ you can have all the information about your pro- gram that the compiler has (well, almost). – this includes trees, symbols and types and more. – you can reflect at run-time (scala.reflect.runtime.universe) or at compile-time (macros).
  • 42. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 21 of 22 Scala Reflection Conclusions In Scala 2.10+ you can have all the information about your pro- gram that the compiler has (well, almost). – this includes trees, symbols and types and more. – you can reflect at run-time (scala.reflect.runtime.universe) or at compile-time (macros). But (Devil’s Advocate) . . . – we are still far from C++ Template Programming, e.g., no factorial at compile time. – Java reflection, even if limited, is easier to use.
  • 43. Reflection in Scala 2.10+ Walter Cazzola Reflection introduction properties example Scala Reflection trees universes examples Macros References Slide 22 of 22 References Martin Odersky. Reflection and Compilers. Keynote at Lang.NEXT, April 2012. Eugene Burmako. Macros. Scala 2.10 documentation, École Polytechnique Fédérale de Lausanne, 2013. Heather Miller, Eugene Burmako, and Philipp Haller. Scala Reflection 2.10. Scala 2.10 documentation, École Polytechnique Fédérale de Lausanne, 2013.