Package scala.reflect.api
package api
Type Members
trait Annotations extends AnyRef
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. When read by Scala reflection, the scala.annotation.ClassfileAnnotation trait is automatically added as a superclass to every Java annotation type.
Scala annotations: annotations on definitions or types produced by the Scala compiler.
When a Scala annotation that inherits from scala.annotation.StaticAnnotation or scala.annotation.ClassfileAnnotation 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 as q"@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
to ann(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 via annotation.tree.children.tail
.
For more information about Annotation
s, see the Reflection Guide: Annotations, Names, Scopes, and More
trait Constants extends AnyRef
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.
scala.reflect.api.Constants#Constant instances represent certain kinds of these expressions (with values stored in the value
field and its strongly-typed views named booleanValue
, intValue
etc.), namely:
-
Literals of primitive value classes (bytes, shorts, ints, longs, floats, doubles, chars, booleans and voids).String literals.References to classes (typically constructed with scala.Predef#classOf).References to enumeration values.
Such constants are used to represent literals in abstract syntax trees (the scala.reflect.api.Trees#Literal node) and literal arguments for Java class file annotations (the scala.reflect.api.Annotations#LiteralArgument class).
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).
enum JavaSimpleEnumeration { FOO, BAR } import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface JavaSimpleAnnotation { Class<?> classRef(); JavaSimpleEnumeration enumRef(); } @JavaSimpleAnnotation( classRef = JavaAnnottee.class, enumRef = JavaSimpleEnumeration.BAR ) public class JavaAnnottee {}
import scala.reflect.runtime.universe._ import scala.reflect.runtime.{currentMirror => cm} object Test extends App { val jann = typeOf[JavaAnnottee].typeSymbol.annotations(0).javaArgs def jarg(name: String) = jann(TermName(name)).asInstanceOf[LiteralArgument].value val classRef = jarg("classRef").typeValue println(showRaw(classRef)) // TypeRef(ThisType(<empty>), JavaAnnottee, List()) println(cm.runtimeClass(classRef)) // class JavaAnnottee val enumRef = jarg("enumRef").symbolValue println(enumRef) // value BAR val siblings = enumRef.owner.info.decls val enumValues = siblings.filter(sym => sym.isVal && sym.isPublic) 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 }
trait Exprs extends AnyRef
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 the Expr
companion object, but then the burden of providing a TreeCreator
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 the in
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 an Expr
is typically scala.reflect.runtime#universe, the default mirror is typically scala.reflect.runtime#currentMirror.
trait FlagSets extends AnyRef
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 the flags
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 with asTerm
, asType
or asClass
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. Can be used for pattern matching, instance tests, serialization and the like.
trait Internals extends AnyRef
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
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
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
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 through Mirror
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 classloader Mirror
, 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 classloader Mirror
s to load Symbol
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 classloader Mirror
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
(or typeOf[Location].typeSymbol
if we needed a ClassSymbol
), which are type safe since we don’t have to use String
s to lookup the Symbol
.
Runtime Mirrors
Runtime Mirror
s make use of both classloader and invoker Mirror
s.
The entry point to Mirror
s for use at runtime is via ru.runtimeMirror(<classloader>)
, where ru
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].declaration(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].declaration(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].declaration(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 classes val 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].declaration(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
trait Names extends AnyRef
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 the List
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
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
This trait defines the concept of positions and operations on them.
- See also
trait Printers extends AnyRef
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 inspected
scala> 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/or printKinds
can additionally be supplied as arguments in a call to showRaw
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
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
and decls
defined in scala.reflect.api.Types#TypeApi. Such scopes support the sorted
method, which sorts members in declaration order.
trait StandardDefinitions extends AnyRef
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
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 and tpnme
for type names
- See also
Names The API for names in Scala reflection.
trait Symbols extends AnyRef
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 the baseClasses
from ClassSymbol
. 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 the symbol
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.
This class is used internally by Scala Reflection, and is not recommended for use in client code.
trait Trees extends AnyRef
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.
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 type T
. Like scala.reflect.Manifest, the prime use case of TypeTag
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, a
TypeTag[List[String]]
contains all type information, in this case, of type scala.List[String]
.
scala.reflect.ClassTag. A partial type descriptor of a Scala type. For example, a
ClassTag[List[String]]
contains only the erased class type information, in this case, of type scala.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]
or ClassTag[T]
for the given type argument T
.
#2 Using an implicit parameter of type TypeTag[T]
, ClassTag[T]
, or WeakTypeTag[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
s
WeakTypeTag[T]
generalizes TypeTag[T]
. Unlike a regular TypeTag
, 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 the WeakTypeTag[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.10 Manifest
types do not have a direct correspondence with a 2.10 "Tag
" type.
-
scala.reflect.OptManifest is not supported.
This is because
Tag
s can reify arbitrary types, so they are always available. -
There is no equivalent for scala.reflect.AnyValManifest. Instead, one can compare their
Tag
with one of the base Tag
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 and ClassTag
s in an upcoming point release. Thus, it is advisable to migrate any Manifest
-based APIs to use Tag
s.
For more information about TypeTag
s, see the Reflection Guide: TypeTags
- See also
scala.reflect.ClassTag, scala.reflect.api.TypeTags#TypeTag, scala.reflect.api.TypeTags#WeakTypeTag
trait Types extends AnyRef
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 argument Int
.
Note: Method typeOf
does not work for types with type parameters, such as typeOf[List[A]]
where A
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
<:<
and weak_<:<
.
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
and declarations
methods (along with their singular counterparts member
and declaration
), which provide the list of definitions associated with that type. For example, to look up the map
method of List
, one can do:
scala> typeOf[List[_]].member("map": TermName) res1: reflect.runtime.universe.Symbol = method map
For more information about Type
s, see the Reflection Guide: Symbols, Trees, and Types
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
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 of Universe
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 import scala.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
© 2002-2019 EPFL, with contributions from Lightbend.
Licensed under the Apache License, Version 2.0.
https://www.scala-lang.org/api/2.12.9/scala-reflect/scala/reflect/api/index.html
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