package api
EXPERIMENTAL
The Scala Reflection API (located in scala-reflect.jar).
In Scala 2.10.0, the Scala Reflection API and its implementation have an "experimental" status. This means that the API and the docs are not complete and can be changed in binary- and source-incompatible manner in 2.10.1. This also means that the implementation has some known issues.
The following types are the backbone of the Scala Reflection API, and serve as a good starting point for information about Scala Reflection:
For more information about Scala Reflection, see the Reflection Guide
- Source
- package.scala
Type Members
- trait Annotations extends AnyRef
EXPERIMENTAL
EXPERIMENTAL
This trait provides annotation support for the reflection API.
In Scala, annotations belong to one of the two categories:
- Java annotations: annotations on definitions produced by the Java compiler, i.e., subtypes of java.lang.annotation.Annotation attached to program definitions.
- Scala annotations: annotations on definitions or types produced by the Scala compiler.
When a Scala annotation that inherits from scala.annotation.StaticAnnotation is compiled, it is stored as special attributes in the corresponding classfile, and not as a Java annotation. Note that subclassing just scala.annotation.Annotation is not enough to have the corresponding metadata persisted for runtime reflection.
Both Java and Scala annotations are represented as typed trees carrying constructor invocations corresponding to the annotation. For instance, the annotation in
@ann(1, 2) class C
is represented asq"@new ann(1, 2)"
.Unlike Java reflection, Scala reflection does not support evaluation of constructor invocations stored in annotations into underlying objects. For instance it's impossible to go from
@ann(1, 2) class C
toann(1, 2)
, so one has to analyze trees representing annotation arguments to manually extract corresponding values. Towards that end, arguments of an annotation can be obtained viaannotation.tree.children.tail
.For more information about
Annotation
s, see the Reflection Guide: Annotations, Names, Scopes, and More - trait Constants extends AnyRef
EXPERIMENTAL
EXPERIMENTAL
According to the section 6.24 "Constant Expressions" of the Scala language specification, certain expressions (dubbed constant expressions) can be evaluated by the Scala compiler at compile-time. Examples include "true", "0" and "classOf[List]".
Constant
instances can be matched against and can be constructed directly, as if they were case classes:assert(Constant(true).value == true) Constant(true) match { case Constant(s: String) => println("A string: " + s) case Constant(b: Boolean) => println("A boolean value: " + b) case Constant(x) => println("Something else: " + x) }
Constant
instances can wrap the following kinds of expressions:- Literals of primitive value classes (
Byte
,Short
,Int
,Long
,Float
,Double
,Char
,Boolean
andUnit
) - represented directly as the corresponding type - String literals - represented as instances of
String
. - References to classes, typically constructed with scala.Predef#classOf - represented as types.
- References to enumeration values - represented as symbols.
Instances are used to represent literals in abstract syntax trees, inside scala.reflect.api.Trees#Literal nodes.
Example
The
value
field deserves some explanation. Primitive and string values are represented as themselves, whereas references to classes and enums are a bit roundabout.Class references are represented as instances of scala.reflect.api.Types#Type (because when the Scala compiler processes a class reference, the underlying runtime class might not yet have been compiled). To convert such a reference to a runtime class, one should use the
runtimeClass
method of a mirror such as scala.reflect.api.Mirrors#RuntimeMirror (the simplest way to get such a mirror is using scala.reflect.runtime.package#currentMirror).Enumeration value references are represented as instances of scala.reflect.api.Symbols#Symbol, which on JVM point to methods that return underlying enum values. To inspect an underlying enumeration or to get runtime value of a reference to an enum, one should use a scala.reflect.api.Mirrors#RuntimeMirror (the simplest way to get such a mirror is again scala.reflect.runtime.package#currentMirror).
// File "JavaSimpleEnumeration.java" enum JavaSimpleEnumeration { FOO, BAR } // File "JavaSimpleAnnotation.java" import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface JavaSimpleAnnotation { Class<?> classRef(); JavaSimpleEnumeration enumRef(); } // File "JavaAnnottee.java" @JavaSimpleAnnotation( classRef = JavaAnnottee.class, enumRef = JavaSimpleEnumeration.BAR ) public class JavaAnnottee {}
val javaArgs = typeOf[JavaAnnottee].typeSymbol.annotations(0).tree.children.tail def jArg[A](lhs: String): Option[A] = javaArgs .map { case NamedArg(lhs, Literal(const)) => (lhs.toString, const) } .find(_._1 == lhs) .map(_._2.value.asInstanceOf[A]) // class reference, cast to Type val classRef = jArg[Type]("classRef").get println(showRaw(classRef)) // TypeRef(ThisType(<empty>), JavaAnnottee, List()) println(cm.runtimeClass(classRef)) // class JavaAnnottee // enum value reference, cast to Symbol val enumRef = jArg[Symbol]("enumRef").get println(enumRef) // value BAR val siblings = enumRef.owner.info.decls val enumValues = siblings.filter(_.isJavaEnum) println(enumValues) // Scope{ // final val FOO: JavaSimpleEnumeration; // final val BAR: JavaSimpleEnumeration // } // doesn't work because of https://github.com/scala/bug/issues/6459 // val enumValue = mirror.reflectField(enumRef.asTerm).get val enumClass = cm.runtimeClass(enumRef.owner.asClass) val enumValue = enumClass.getDeclaredField(enumRef.name.toString).get(null) println(enumValue) // BAR
- Literals of primitive value classes (
- trait Exprs extends AnyRef
EXPERIMENTAL
EXPERIMENTAL
A trait that defines strongly-typed tree wrappers and operations on them for use in Scala Reflection.
Expr
wraps an abstract syntax tree (scala.reflect.api.Trees#Tree) and tags it with its type (scala.reflect.api.Types#Type).Usually
Expr
s are created via scala.reflect.api.Universe#reify, in which case a compiler produces a scala.reflect.api.TreeCreator for the provided expression and also creates a complementary scala.reflect.api.TypeTags#WeakTypeTag that corresponds to the type of that expression.Expr
s can also be created manually via theExpr
companion object, but then the burden of providing aTreeCreator
lies on the programmer. Compile-time reflection via macros, as described in scala.reflect.macros.Aliases, provides an easier way to instantiate exprs manually. Manual creation, however, is very rarely needed when working with runtime reflection.Expr
can be migrated from one mirror to another by using thein
method. Migration means that all symbolic references to classes/objects/packages in the expression are re-resolved within the new mirror (typically using that mirror's classloader). The default universe of anExpr
is typically scala.reflect.runtime#universe, the default mirror is typically scala.reflect.runtime#currentMirror. - trait FlagSets extends AnyRef
EXPERIMENTAL
EXPERIMENTAL
The trait that defines flag sets and operations on them.
Flag
s are used to provide modifiers for abstract syntax trees that represent definitions via theflags
field of scala.reflect.api.Trees#Modifiers. Trees that accept modifiers are:- scala.reflect.api.Trees#ClassDef. Classes and traits.
- scala.reflect.api.Trees#ModuleDef. Objects.
- scala.reflect.api.Trees#ValDef. Vals, vars, parameters and self-type annotations.
- scala.reflect.api.Trees#DefDef. Methods and constructors.
- scala.reflect.api.Trees#TypeDef. Type aliases, abstract type members and type parameters.
For example, to create a class named
C
one would write something like:ClassDef(Modifiers(NoFlags), TypeName("C"), Nil, ...)
Here, the flag set is empty.
To make
C
private, one would write something like:ClassDef(Modifiers(PRIVATE), TypeName("C"), Nil, ...)
Flags can also be combined with the vertical bar operator (
|
). For example, a private final class is written something like:ClassDef(Modifiers(PRIVATE | FINAL), TypeName("C"), Nil, ...)
The list of all available flags is defined in scala.reflect.api.FlagSets#FlagValues, available via scala.reflect.api.FlagSets#Flag. (Typically one writes a wildcard import for this, e.g.
import scala.reflect.runtime.universe.Flag._
).Definition trees are compiled down to symbols, so flags on modifiers of these trees are transformed into flags on the resulting symbols. Unlike trees, symbols don't expose flags, but rather provide
isXXX
test methods (e.g.isFinal
can be used to test finality). These test methods might require an upcast withasTerm
,asType
orasClass
as some flags only make sense for certain kinds of symbols.Of Note: This part of the Reflection API is being considered as a candidate for redesign. It is quite possible that in future releases of the reflection API, flag sets could be replaced with something else.
For more details about
FlagSet
s and other aspects of Scala reflection, see the Reflection Guide - trait ImplicitTags extends AnyRef
Tags which preserve the identity of abstract types in the face of erasure.
Tags which preserve the identity of abstract types in the face of erasure. Can be used for pattern matching, instance tests, serialization and the like.
- trait Internals extends AnyRef
EXPERIMENTAL
EXPERIMENTAL
This trait assembles APIs occasionally necessary for performing low-level operations on reflection artifacts. See Internals#InternalApi for more information about nature, usefulness and compatibility guarantees of these APIs.
- trait JavaUniverse extends Universe
EXPERIMENTAL
EXPERIMENTAL
A refinement of scala.reflect.api.Universe for runtime reflection using JVM classloaders.
This refinement equips mirrors with reflection capabilities for the JVM.
JavaMirror
can convert Scala reflection artifacts (symbols and types) into Java reflection artifacts (classes) and vice versa. It can also perform reflective invocations (getting/setting field values, calling methods, etc).See the Reflection Guide for details on how to use runtime reflection.
- trait Liftables extends AnyRef
- abstract class Mirror[U <: Universe with Singleton] extends AnyRef
EXPERIMENTAL
EXPERIMENTAL
The base class for all mirrors.
See scala.reflect.api.Mirrors or Reflection Guide for a complete overview of
Mirror
s.- U
the type of the universe this mirror belongs to.
- trait Mirrors extends AnyRef
EXPERIMENTAL
EXPERIMENTAL
This trait provides support for Mirrors in the Scala Reflection API.
Mirror
s are a central part of Scala Reflection. All information provided by reflection is made accessible throughMirror
s. Depending on the type of information to be obtained, or the reflective action to be taken, different flavors of mirrors must be used. "Classloader" mirrors can be used to obtain representations of types and members. From a classloaderMirror
, it's possible to obtain more specialized "invoker"Mirror
s (the most commonly-used mirrors), which implement reflective invocations, such as method/constructor calls and field accesses.The two flavors of mirrors:
- “Classloader” mirrors. These mirrors translate names to symbols
(via methods
staticClass
/staticModule
/staticPackage
). - "Invoker” mirrors. These mirrors implement reflective invocations
(via methods
MethodMirror.apply
,FieldMirror.get
, etc). These "invoker" mirrors are the types of mirrors that are most commonly used.
Compile-time Mirrors
Compile-time
Mirror
s make use of only classloaderMirror
s to loadSymbol
s by name.The entry point to classloader
Mirror
s is via scala.reflect.macros.blackbox.Context#mirror or scala.reflect.macros.whitebox.Context#mirror. Typical methods which use classloaderMirror
s include scala.reflect.api.Mirror#staticClass, scala.reflect.api.Mirror#staticModule, and scala.reflect.api.Mirror#staticPackage. For example:import scala.reflect.macros.blackbox.Context case class Location(filename: String, line: Int, column: Int) object Macros { def currentLocation: Location = macro impl def impl(c: Context): c.Expr[Location] = { import c.universe._ val pos = c.macroApplication.pos val clsLocation = c.mirror.staticModule("Location") // get symbol of "Location" object c.Expr(Apply(Ident(clsLocation), List(Literal(Constant(pos.source.path)), Literal(Constant(pos.line)), Literal(Constant(pos.column))))) } }
Of Note: There are several high-level alternatives that one can use to avoid having to manually lookup symbols. For example,
typeOf[Location.type].termSymbol
(ortypeOf[Location].typeSymbol
if we needed aClassSymbol
), which are type safe since we don’t have to useString
s to lookup theSymbol
.Runtime Mirrors
Runtime
Mirror
s make use of both classloader and invokerMirror
s.The entry point to
Mirror
s for use at runtime is viaru.runtimeMirror(<classloader>)
, whereru
is scala.reflect.runtime.universe.The result of a scala.reflect.api.JavaUniverse#runtimeMirror call is a classloader mirror, of type scala.reflect.api.Mirrors#ReflectiveMirror, which can load symbols by names as discussed above (in the “Compile-time” section).
A classloader mirror can create invoker mirrors, which include: scala.reflect.api.Mirrors#InstanceMirror, scala.reflect.api.Mirrors#MethodMirror, scala.reflect.api.Mirrors#FieldMirror, scala.reflect.api.Mirrors#ClassMirror and scala.reflect.api.Mirrors#ModuleMirror.
Examples of how these two types of
Mirror
s interact are available below.Types of Mirrors, Their Use Cases & Examples
scala.reflect.api.Mirrors#ReflectiveMirror. Used for loading
Symbol
s by name, and as an entry point into invoker mirrors. Entry point:val m = ru.runtimeMirror(<classloader>)
. Example:scala> val ru = scala.reflect.runtime.universe ru: scala.reflect.api.JavaUniverse = ... scala> val m = ru.runtimeMirror(getClass.getClassLoader) m: reflect.runtime.universe.Mirror = JavaMirror ...
scala.reflect.api.Mirrors#InstanceMirror. Used for creating invoker
Mirror
s for methods and fields and for inner classes and inner objects (modules). Entry point:val im = m.reflect(<value>)
. Example:scala> class C { def x = 2 } defined class C scala> val im = m.reflect(new C) im: reflect.runtime.universe.InstanceMirror = instance mirror for C@3442299e
scala.reflect.api.Mirrors#MethodMirror. Used for invoking instance methods (Scala only has instance methods-- methods of objects are instance methods of object instances, obtainable via
ModuleMirror.instance
). Entry point:val mm = im.reflectMethod(<method symbol>)
. Example:scala> val methodX = typeOf[C].decl(TermName("x")).asMethod methodX: reflect.runtime.universe.MethodSymbol = method x scala> val mm = im.reflectMethod(methodX) mm: reflect.runtime.universe.MethodMirror = method mirror for C.x: scala.Int (bound to C@3442299e) scala> mm() res0: Any = 2
scala.reflect.api.Mirrors#FieldMirror. Used for getting/setting instance fields (Scala only has instance fields-- fields of objects are instance methods of object instances obtainable via ModuleMirror.instance). Entry point:
val fm = im.reflectMethod(<field or accessor symbol>)
. Example:scala> class C { val x = 2; val y = 3 } defined class C scala> val m = ru.runtimeMirror(getClass.getClassLoader) m: reflect.runtime.universe.Mirror = JavaMirror ... scala> val im = m.reflect(new C) im: reflect.runtime.universe.InstanceMirror = instance mirror for C@5f0c8ac1 scala> val fieldX = typeOf[C].decl(TermName("x")).asTerm.accessed.asTerm fieldX: reflect.runtime.universe.TermSymbol = value x scala> val fmX = im.reflectField(fieldX) fmX: reflect.runtime.universe.FieldMirror = field mirror for C.x (bound to C@5f0c8ac1) scala> fmX.get res0: Any = 2 scala> fmX.set(3) // NOTE: can set an underlying value of an immutable field! scala> val fieldY = typeOf[C].decl(TermName("y")).asTerm.accessed.asTerm fieldY: reflect.runtime.universe.TermSymbol = variable y scala> val fmY = im.reflectField(fieldY) fmY: reflect.runtime.universe.FieldMirror = field mirror for C.y (bound to C@5f0c8ac1) scala> fmY.get res1: Any = 3 scala> fmY.set(4) scala> fmY.get res2: Any = 4
scala.reflect.api.Mirrors#ClassMirror. Used for creating invoker mirrors for constructors. Entry points: for static classes
val cm1 = m.reflectClass(<class symbol>)
, for inner classesval mm2 = im.reflectClass(<class symbol>)
. Example:scala> case class C(x: Int) defined class C scala> val m = ru.runtimeMirror(getClass.getClassLoader) m: reflect.runtime.universe.Mirror = JavaMirror ... scala> val classC = typeOf[C].typeSymbol.asClass classC: reflect.runtime.universe.Symbol = class C scala> val cm = m.reflectClass(classC) cm: reflect.runtime.universe.ClassMirror = class mirror for C (bound to null) scala> val ctorC = typeOf[C].decl(ru.nme.CONSTRUCTOR).asMethod ctorC: reflect.runtime.universe.MethodSymbol = constructor C scala> val ctorm = cm.reflectConstructor(ctorC) ctorm: reflect.runtime.universe.MethodMirror = constructor mirror for C.<init>(x: scala.Int): C (bound to null) scala> ctorm(2) res0: Any = C(2)
scala.reflect.api.Mirrors#ModuleMirror. Used for getting singleton instances of objects. Entry points: for static objects (modules)
val mm1 = m.reflectModule(<module symbol>)
, for inner objects (modules)val mm2 = im.reflectModule(<module symbol>)
. Example:scala> object C { def x = 2 } defined module C scala> val m = ru.runtimeMirror(getClass.getClassLoader) m: reflect.runtime.universe.Mirror = JavaMirror ... scala> val objectC = typeOf[C.type].termSymbol.asModule objectC: reflect.runtime.universe.ModuleSymbol = object C scala> val mm = m.reflectModule(objectC) mm: reflect.runtime.universe.ModuleMirror = module mirror for C (bound to null) scala> val obj = mm.instance obj: Any = C$@1005ec04
For more information about
Mirrors
s, see the Reflection Guide: Mirrors - “Classloader” mirrors. These mirrors translate names to symbols
(via methods
- trait Names extends AnyRef
EXPERIMENTAL
EXPERIMENTAL
This trait defines
Name
s in Scala Reflection, and operations on them.Names are simple wrappers for strings. Name has two subtypes TermName and TypeName which distinguish names of terms (like objects or members) and types. A term and a type of the same name can co-exist in an object.
To search for the
map
method (which is a term) declared in theList
class, one can do:scala> typeOf[List[_]].member(TermName("map")) res0: reflect.runtime.universe.Symbol = method map
To search for a type member, one can follow the same procedure, using
TypeName
instead.For more information about creating and using
Name
s, see the Reflection Guide: Annotations, Names, Scopes, and More - trait Position extends Attachments
EXPERIMENTAL
EXPERIMENTAL
Position tracks the origin of symbols and tree nodes. They are commonly used when displaying warnings and errors, to indicate the incorrect point in the program.
Every non-empty position refers to a SourceFile and three character offsets within it: start, end, and point. The point is where the ^ belongs when issuing an error message, usually a Name. A range position can be designated as transparent, which excuses it from maintaining the invariants to follow. If a transparent position has opaque children, those are considered as if they were the direct children of the transparent position's parent.
Note: some of these invariants actually apply to the trees which carry the positions, but they are phrased as if the positions themselves were the parent/children for conciseness.
Invariant 1: in a focused/offset position, start == point == end Invariant 2: in a range position, start <= point < end Invariant 3: an offset position never has a child with a range position Invariant 4: every range position child of a range position parent is contained within its parent Invariant 5: opaque range position siblings overlap at most at a single point
The following tests are useful on positions:
pos.isDefined true if position is not an UndefinedPosition (those being NoPosition and FakePos) pos.isRange true if position is a range (opaque or transparent) which implies start < end pos.isOpaqueRange true if position is an opaque range
The following accessor methods are provided - an exception will be thrown if point/start/end are attempted on an UndefinedPosition.
pos.source The source file of the position, or NoSourceFile if unavailable pos.point The offset of the point pos.start The (inclusive) start offset, or the point of an offset position pos.end The (exclusive) end offset, or the point of an offset position
The following conversion methods are often used:
pos.focus Converts a range position to an offset position focused on the point pos.makeTransparent Convert an opaque range into a transparent range
For more information about
Position
s, see the Reflection Guide: Annotations, Names, Scopes, and More - trait Positions extends AnyRef
EXPERIMENTAL
EXPERIMENTAL
This trait defines the concept of positions and operations on them.
- See also
- trait Printers extends AnyRef
EXPERIMENTAL
EXPERIMENTAL
Utilities for nicely printing scala.reflect.api.Trees and scala.reflect.api.Types.
Printing Trees
The method
show
displays the "prettified" representation of reflection artifacts. This representation provides one with the desugared Java representation of Scala code. For example:scala> import scala.reflect.runtime.universe._ import scala.reflect.runtime.universe._ scala> def tree = reify{ final class C { def x = 2 } }.tree tree: reflect.runtime.universe.Tree scala> show(tree) res0: String = { final class C extends AnyRef { def <init>() = { super.<init>(); () }; def x = 2 }; () }
The method
showRaw
displays internal structure of a given reflection object as a Scala abstract syntax tree (AST), the representation that the Scala typechecker operates on.Note, that while this representation appears to generate correct trees that one might think would be possible to use in a macro implementation, this is not usually the case. Symbols aren't fully represented (only their names are). Thus, this method is best-suited for use simply inspecting ASTs given some valid Scala code.
scala> showRaw(tree) res1: String = Block(List( ClassDef(Modifiers(FINAL), TypeName("C"), List(), Template( List(Ident(TypeName("AnyRef"))), noSelfType, List( DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List( Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), Literal(Constant(())))), DefDef(Modifiers(), TermName("x"), List(), List(), TypeTree(), Literal(Constant(2))))))), Literal(Constant(())))
The method
showRaw
can also print scala.reflect.api.Types next to the artifacts being inspectedscala> import scala.tools.reflect.ToolBox // requires scala-compiler.jar import scala.tools.reflect.ToolBox scala> import scala.reflect.runtime.{currentMirror => cm} import scala.reflect.runtime.{currentMirror=>cm} scala> showRaw(cm.mkToolBox().typecheck(tree), printTypes = true) res2: String = Block[1](List( ClassDef[2](Modifiers(FINAL), TypeName("C"), List(), Template[3]( List(Ident[4](TypeName("AnyRef"))), noSelfType, List( DefDef[2](Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree[3](), Block[1](List( Apply[4](Select[5](Super[6](This[3](TypeName("C")), tpnme.EMPTY), ...))), Literal[1](Constant(())))), DefDef[2](Modifiers(), TermName("x"), List(), List(), TypeTree[7](), Literal[8](Constant(2))))))), Literal[1](Constant(()))) [1] TypeRef(ThisType(scala), scala.Unit, List()) [2] NoType [3] TypeRef(NoPrefix, TypeName("C"), List()) [4] TypeRef(ThisType(java.lang), java.lang.Object, List()) [5] MethodType(List(), TypeRef(ThisType(java.lang), java.lang.Object, List())) [6] SuperType(ThisType(TypeName("C")), TypeRef(... java.lang.Object ...)) [7] TypeRef(ThisType(scala), scala.Int, List()) [8] ConstantType(Constant(2))
Printing Types
The method
show
scala> import scala.reflect.runtime.universe._ import scala.reflect.runtime.universe._ scala> def tpe = typeOf[{ def x: Int; val y: List[Int] }] tpe: reflect.runtime.universe.Type scala> show(tpe) res0: String = scala.AnyRef{def x: Int; val y: scala.List[Int]}
Like the method
showRaw
for scala.reflect.api.Trees,showRaw
for scala.reflect.api.Types provides a visualization of the Scala AST operated on by the Scala typechecker.// showRaw has already been discussed above scala> showRaw(tpe) res1: String = RefinedType( List(TypeRef(ThisType(scala), TypeName("AnyRef"), List())), Scope( TermName("x"), TermName("y")))
printIds
and/orprintKinds
can additionally be supplied as arguments in a call toshowRaw
which additionally shows the unique identifiers of symbols.scala> showRaw(tpe, printIds = true, printKinds = true) res2: String = RefinedType( List(TypeRef(ThisType(scala#2043#PK), TypeName("AnyRef")#691#TPE, List())), Scope( TermName("x")#2540#METH, TermName("y")#2541#GET))
For more details about
Printer
s and other aspects of Scala reflection, see the Reflection Guide - trait Quasiquotes extends AnyRef
- trait Scopes extends AnyRef
EXPERIMENTAL
EXPERIMENTAL
This trait provides support for scopes in the reflection API.
A scope object generally maps names to symbols available in a corresponding lexical scope. Scopes can be nested. The base type exposed to the reflection API, however, only exposes a minimal interface, representing a scope as an iterable of symbols.
For rare occasions when it is necessary to create a scope manually, e.g., to populate members of scala.reflect.api.Types#RefinedType, there is the
newScopeWith
function.Additional functionality is exposed in member scopes that are returned by
members
anddecls
defined in scala.reflect.api.Types#TypeApi. Such scopes support thesorted
method, which sorts members in declaration order. - trait StandardDefinitions extends AnyRef
EXPERIMENTAL
EXPERIMENTAL
All Scala standard symbols and types.
These standard definitions can accessed to using
definitions
. They're typically imported with a wildcard import,import definitions._
, and are listed in scala.reflect.api.StandardDefinitions#DefinitionsApi. - trait StandardLiftables extends AnyRef
- trait StandardNames extends AnyRef
EXPERIMENTAL
EXPERIMENTAL
Standard names are names that are essential to creating trees or to reflecting Scala artifacts. For example,
CONSTRUCTOR
(aka<init>
on JVM) is necessary to create and invoke constructors.These standard names can be referred to using
nme
for term names andtpnme
for type names- See also
Names The API for names in Scala reflection.
- trait Symbols extends AnyRef
EXPERIMENTAL
EXPERIMENTAL
This trait defines symbols and operations on them.
Symbols are used to establish bindings between a name and the entity it refers to, such as a class or a method. Anything you define and can give a name to in Scala has an associated symbol.
Symbols contain all available information about the declaration of an entity (class/object/trait etc.) or a member (vals/vars/defs etc.), and as such are an integral abstraction central to both runtime reflection and macros.
A symbol can provide a wealth of information ranging from the basic
name
method available on all symbols to other, more involved, concepts such as getting thebaseClasses
fromClassSymbol
. Other common use cases of symbols include inspecting members' signatures, getting type parameters of a class, getting the parameter type of a method or finding out the type of a field.Example usage of runtime reflection; getting a method's type signature:
scala> import scala.reflect.runtime.universe._ import scala.reflect.runtime.universe._ scala> class C[T] { def test[U](x: T)(y: U): Int = ??? } defined class C scala> val test = typeOf[C[Int]].member(TermName("test")).asMethod test: reflect.runtime.universe.MethodSymbol = method test scala> test.info res0: reflect.runtime.universe.Type = [U](x: T)(y: U)scala.Int
Symbols are organized in a hierarchy. For example, a symbol that represents a parameter of a method is owned by the corresponding method symbol, a method symbol is owned by its enclosing class, a class is owned by a containing package and so on.
Certain types of tree nodes, such as Ident (references to identifiers) and Select (references to members) expose method
symbol
to obtain the symbol that represents their declaration. During the typechecking phase, the compiler looks up the symbol based on the name and scope and sets thesymbol
field of tree nodes.For more information about
Symbol
usage and attached intricacies, see the Reflection Guide: Symbols - abstract class TreeCreator extends Serializable
A mirror-aware factory for trees.
A mirror-aware factory for trees.
This class is used internally by Scala Reflection, and is not recommended for use in client code.
- trait Trees extends AnyRef
EXPERIMENTAL
EXPERIMENTAL
This trait defines the node types used in Scala abstract syntax trees (AST) and operations on them.
Trees are the basis for Scala's abstract syntax that is used to represent programs. They are also called abstract syntax trees and commonly abbreviated as ASTs.
In Scala reflection, APIs that produce or use
Tree
s are:- Annotations which use trees to represent their arguments, exposed in Annotation.scalaArgs.
- reify, a special method on scala.reflect.api.Universe that takes an expression and returns an AST which represents the expression.
- Macros and runtime compilation with toolboxes which both use trees as their program representation medium.
Trees are immutable, except for three fields pos, symbol, and tpe, which are assigned when a tree is typechecked to attribute it with the information gathered by the typechecker.
Examples
The following creates an AST representing a literal 5 in Scala source code:
Literal(Constant(5))
The following creates an AST representing
print("Hello World")
:Apply(Select(Select(This(TypeName("scala")), TermName("Predef")), TermName("print")), List(Literal(Constant("Hello World"))))
The following creates an AST from a literal 5, and then uses
showRaw
to print it in a readable format.import scala.reflect.runtime.universe.{ reify, showRaw } print( showRaw( reify{5}.tree ) )` // prints Literal(Constant(5))
For more information about
Tree
s, see the Reflection Guide: Symbols, Trees, Types. - abstract class TypeCreator extends Serializable
A mirror-aware factory for types.
A mirror-aware factory for types.
This class is used internally by Scala Reflection, and is not recommended for use in client code.
- trait TypeTags extends AnyRef
A
TypeTag[T]
encapsulates the runtime type representation of some typeT
.A
TypeTag[T]
encapsulates the runtime type representation of some typeT
. Like scala.reflect.Manifest, the prime use case ofTypeTag
s is to give access to erased types. However,TypeTag
s should be considered to be a richer replacement of the pre-2.10 notion of a Manifest, that are, in addition, fully integrated with Scala reflection.There exist three different types of
TypeTags
:- scala.reflect.api.TypeTags#TypeTag.
A full type descriptor of a Scala type. For example, aTypeTag[List[String]]
contains all type information, in this case, of typescala.List[String]
. - scala.reflect.ClassTag.
A partial type descriptor of a Scala type. For example, aClassTag[List[String]]
contains only the erased class type information, in this case, of typescala.collection.immutable.List
.ClassTag
s provide access only to the runtime class of a type. Analogous to scala.reflect.ClassManifest - scala.reflect.api.TypeTags#WeakTypeTag.
A type descriptor for abstract types (see description below).
Like Manifests,
TypeTag
s are always generated by the compiler, and can be obtained in three ways:#1 Via the methods typeTag, classTag, or weakTypeTag
For example:
import scala.reflect.runtime.universe._ val tt = typeTag[Int] import scala.reflect._ val ct = classTag[String]
Each of these methods constructs a
TypeTag[T]
orClassTag[T]
for the given type argumentT
.#2 Using an implicit parameter of type
TypeTag[T]
,ClassTag[T]
, orWeakTypeTag[T]
For example:
import scala.reflect.runtime.universe._ def paramInfo[T](x: T)(implicit tag: TypeTag[T]): Unit = { val targs = tag.tpe match { case TypeRef(_, _, args) => args } println(s"type of $x has type arguments $targs") } scala> paramInfo(42) type of 42 has type arguments List() scala> paramInfo(List(1, 2)) type of List(1, 2) has type arguments List(Int)
#3 Context bound of a type parameter
...on methods or classes. The above example can be implemented as follows:
import scala.reflect.runtime.universe._ def paramInfo[T: TypeTag](x: T): Unit = { val targs = typeOf[T] match { case TypeRef(_, _, args) => args } println(s"type of $x has type arguments $targs") } scala> paramInfo(42) type of 42 has type arguments List() scala> paramInfo(List(1, 2)) type of List(1, 2) has type arguments List(Int)
WeakTypeTag
sWeakTypeTag[T]
generalizesTypeTag[T]
. Unlike a regularTypeTag
, components of its type representation can be references to type parameters or abstract types. However,WeakTypeTag[T]
tries to be as concrete as possible, i.e. if type tags are available for the referenced type arguments or abstract types, they are used to embed the concrete types into theWeakTypeTag[T]
.Continuing the example above:
def weakParamInfo[T](x: T)(implicit tag: WeakTypeTag[T]): Unit = { val targs = tag.tpe match { case TypeRef(_, _, args) => args } println(s"type of $x has type arguments $targs") } scala> def foo[T] = weakParamInfo(List[T]()) foo: [T]=> Unit scala> foo[Int] type of List() has type arguments List(T)
TypeTags and Manifests
TypeTag
s correspond loosely to the pre-2.10 notion of scala.reflect.Manifests. While scala.reflect.ClassTag corresponds to scala.reflect.ClassManifest and scala.reflect.api.TypeTags#TypeTag mostly corresponds to scala.reflect.Manifest, other pre-2.10Manifest
types do not have a direct correspondence with a 2.10 "Tag
" type.- scala.reflect.OptManifest is not supported.
This is becauseTag
s can reify arbitrary types, so they are always available. - - There is no equivalent for scala.reflect.AnyValManifest.
Instead, one can compare theirTag
with one of the baseTag
s (defined in the corresponding companion objects) in order to find out whether or not it represents a primitive value class. Additionally, it's possible to simply use<tag>.tpe.typeSymbol.isPrimitiveValueClass
. - There are no replacement for factory methods defined in the
Manifest
companion objects.
Instead, one could generate corresponding types using the reflection APIs provided by Java (for classes) and Scala (for types). - Certain manifest operations(i.e., <:<, >:> and typeArguments) are not
supported.
Instead, one could use the reflection APIs provided by Java (for classes) and Scala (for types).
In Scala 2.10, scala.reflect.ClassManifests are deprecated, and it is planned to deprecate scala.reflect.Manifest in favor of
TypeTag
s andClassTag
s in an upcoming point release. Thus, it is advisable to migrate anyManifest
-based APIs to useTag
s.For more information about
TypeTag
s, see the Reflection Guide: TypeTags - scala.reflect.api.TypeTags#TypeTag.
- trait Types extends AnyRef
EXPERIMENTAL
EXPERIMENTAL
A trait that defines types and operations on them.
Type instances represent information about the type of a corresponding symbol. This includes its members (methods, fields, type parameters, nested classes, traits, etc.) either declared directly or inherited, its base types, its erasure and so on. Types also provide operations to test for type conformance or equivalence or for widening.
To instantiate a type, most of the time, the scala.reflect.api.TypeTags#typeOf method can be used. It takes a type argument and produces a
Type
instance which represents that argument. For example:scala> typeOf[List[Int]] res0: reflect.runtime.universe.Type = scala.List[Int]
In this example, a scala.reflect.api.Types#TypeRef is returned, which corresponds to the type constructor
List
applied to the type argumentInt
.In the case of a generic type, you can also combine it with other types using scala.reflect.api.Types#appliedType. For example:
scala> val intType = typeOf[Int] intType: reflect.runtime.universe.Type = Int scala> val listType = typeOf[List[_]] listType: reflect.runtime.universe.Type = List[_] scala> appliedType(listType.typeConstructor, intType) res0: reflect.runtime.universe.Type = List[Int]
Note: Method
typeOf
does not work for types with type parameters, such astypeOf[List[A]]
whereA
is a type parameter. In this case, use scala.reflect.api.TypeTags#weakTypeOf instead.For other ways to instantiate types, see the corresponding section of the Reflection Guide.
Common Operations on Types
Types are typically used for type conformance tests or are queried for declarations of members or inner types.
- Subtyping Relationships can be tested using
<:<
andweak_<:<
. - Type Equality can be checked with
=:=
. It's important to note that==
should not be used to compare types for equality--==
can't check for type equality in the presence of type aliases, while=:=
can.
Types can be queried for members and declarations by using the
members
anddeclarations
methods (along with their singular counterpartsmember
anddeclaration
), which provide the list of definitions associated with that type. For example, to look up themap
method ofList
, one can do:scala> typeOf[List[_]].member(TermName("map")) res1: reflect.runtime.universe.Symbol = method map
For more information about
Type
s, see the Reflection Guide: Symbols, Trees, and Types - Subtyping Relationships can be tested using
- abstract class Universe extends Symbols with Types with FlagSets with Scopes with Names with Trees with Constants with Annotations with Positions with Exprs with TypeTags with ImplicitTags with StandardDefinitions with StandardNames with StandardLiftables with Mirrors with Printers with Liftables with Quasiquotes with Internals
EXPERIMENTAL
EXPERIMENTAL
Universe
provides a complete set of reflection operations which make it possible for one to reflectively inspect Scala type relations, such as membership or subtyping.scala.reflect.api.Universe has two specialized sub-universes for different scenarios. scala.reflect.api.JavaUniverse adds operations that link symbols and types to the underlying classes and runtime values of a JVM instance-- this can be thought of as the
Universe
that should be used for all typical use-cases of Scala reflection. scala.reflect.macros.Universe adds operations which allow macros to access selected compiler data structures and operations-- this type ofUniverse
should only ever exist within the implementation of a Scala macro.Universe
can be thought of as the entry point to Scala reflection. It mixes-in, and thus provides an interface to the following main types:- Types represent types
- Symbols represent definitions
- Trees represent abstract syntax trees
- Names represent term and type names
- Annotations represent annotations
- Positions represent source positions of tree nodes
- FlagSet represent sets of flags that apply to symbols and definition trees
- Constants represent compile-time constants.
To obtain a
Universe
to use with Scala runtime reflection, simply make sure to use or importscala.reflect.runtime.universe._
scala> import scala.reflect.runtime.universe._ import scala.reflect.runtime.universe._ scala> typeOf[List[Int]] res0: reflect.runtime.universe.Type = scala.List[Int] scala> typeOf[Either[String, Int]] res1: reflect.runtime.universe.Type = scala.Either[String,Int]
To obtain a
Universe
for use within a Scala macro, use scala.reflect.macros.blackbox.Context#universe. or scala.reflect.macros.whitebox.Context#universe. For example:def printf(format: String, params: Any*): Unit = macro impl def impl(c: Context)(format: c.Expr[String], params: c.Expr[Any]*): c.Expr[Unit] = { import c.universe._ ... }
For more information about
Universe
s, see the Reflection Guide: Universes
Scala Reflection API
Tags
Implicit values that provide ClassTags
for the reflection
classes. These are abstract in the interface but are later filled in to provide ClassTags
for the either the runtime reflection or macros entities, depending on the use.