From 92dc8f81130b26475b0540a2226c340caac4c9ac Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Mon, 8 Oct 2012 17:44:27 +0200 Subject: reflection docs improvements and moves to doc page --- .../scala/reflect/macros/runtime/Typers.scala | 3 + src/reflect/scala/reflect/api/JavaMirrors.scala | 8 +- src/reflect/scala/reflect/api/Names.scala | 35 ++-- src/reflect/scala/reflect/api/Positions.scala | 5 +- src/reflect/scala/reflect/api/package.scala | 206 +-------------------- 5 files changed, 23 insertions(+), 234 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/reflect/macros/runtime/Typers.scala b/src/compiler/scala/reflect/macros/runtime/Typers.scala index be70181126..f9add91b9a 100644 --- a/src/compiler/scala/reflect/macros/runtime/Typers.scala +++ b/src/compiler/scala/reflect/macros/runtime/Typers.scala @@ -8,6 +8,9 @@ trait Typers { def openImplicits: List[(Type, Tree)] = callsiteTyper.context.openImplicits + /** + * @see [[scala.tools.reflect.Toolbox.typeCheck]] + */ def typeCheck(tree: Tree, pt: Type = universe.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree = { macroLogVerbose("typechecking %s with expected type %s, implicit views = %s, macros = %s".format(tree, pt, !withImplicitViewsDisabled, !withMacrosDisabled)) val context = callsiteTyper.context diff --git a/src/reflect/scala/reflect/api/JavaMirrors.scala b/src/reflect/scala/reflect/api/JavaMirrors.scala index e1219b2dde..e51047a7fe 100644 --- a/src/reflect/scala/reflect/api/JavaMirrors.scala +++ b/src/reflect/scala/reflect/api/JavaMirrors.scala @@ -3,11 +3,9 @@ package api /** A refinement of [[scala.reflect.api.Mirror]] for runtime reflection using JVM classloaders. * - * With this upgrade, mirrors become capable of converting Scala reflection artifacts (symbols and types) - * into Java reflection artifacts (classes) and vice versa. Consequently refined mirrors - * become capable of performing reflective invocations (getting/settings field values, calling methods, etc). - * - * See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection. + * 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/settings field values, calling methods, etc). */ trait JavaMirrors { self: JavaUniverse => diff --git a/src/reflect/scala/reflect/api/Names.scala b/src/reflect/scala/reflect/api/Names.scala index c1de49a475..dccdd6868b 100644 --- a/src/reflect/scala/reflect/api/Names.scala +++ b/src/reflect/scala/reflect/api/Names.scala @@ -1,33 +1,20 @@ package scala.reflect package api -/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines names and operations on them. - * See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern. - * - * Scala has separate namespaces for term names and type names. For example it is possible to have - * a class named `C` and an object named `C` declared in the same lexical scope. - * - * Therefore the Scala reflection API models names using strongly-typed objects rather than strings: - * [[scala.reflect.api.Names#TermName]] and [[scala.reflect.api.Names#TypeName]]. - * - * A Name wraps a string as the name for either a type ([[TypeName]]) of a term ([[TermName]]). - * Two names are equal, if the wrapped string are equal and they are either both `TypeName` or both `TermName`. - * The same string can co-exist as a `TypeName` and a `TermName`, but they would not be equal. - * Names are interned. That is, for two names `name1` and `name2`, `name1 == name2` implies `name1 eq name2`. - * Name instances also can perform mangling and unmangling of symbolic names. - * +/** This trait defines Names (a Scala reflection concept) and operations on them. + * + * Names are simple wrappers for strings. [[scala.reflect.api.Names#Name Name]] has two subtypes [[scala.reflect.api.Names#TermName TermName]] and [[scala.reflect.api.Names#TypeName 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. + * + * @see [[http://docs.scala-lang.org/overviews/reflection/overview.html]]. + * === Examples === * - * To search for the `map` method declared in the `List` class, one uses - * `typeOf[List[_]].member(newTermName("map"))` to explicitly specify that a term is looked up. - * - * An alternative notation makes use of implicit conversions from `String` to `TermName` and `TypeName`: - * `typeOf[List[_]].member("map": TermName)`. Note that there's no implicit conversion from `String` to `Name`, - * because it would be unclear whether such a conversion should produce a term name or a type name. + * To search for the `map` method (which is a term) declared in the `List` class, + * use `typeOf[List[_]].member(newTermName("map"))`. To search for a type member, use + * newTypeName instead. * - * Finally some names that bear special meaning for the compiler are defined in [[scala.reflect.api.StandardNames]]. - * For example, `WILDCARD` represents `_` and `CONSTRUCTOR` represents the standard JVM name for constructors, ``. - * Prefer using such constants instead of spelling the names out explicitly. */ trait Names { /** An implicit conversion from String to TermName. diff --git a/src/reflect/scala/reflect/api/Positions.scala b/src/reflect/scala/reflect/api/Positions.scala index a47dc00f3d..bbb1fe45c4 100644 --- a/src/reflect/scala/reflect/api/Positions.scala +++ b/src/reflect/scala/reflect/api/Positions.scala @@ -1,10 +1,9 @@ package scala.reflect package api -/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines positions and operations on them. - * See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern. +/** This trait defines the concept of positions and operations on them. * - * The main documentation entry about positions is located at [[scala.reflect.api.Position]]. + * @see [[scala.reflect.api.Position]] */ trait Positions { self: Universe => diff --git a/src/reflect/scala/reflect/api/package.scala b/src/reflect/scala/reflect/api/package.scala index d3eef59228..a11a269523 100644 --- a/src/reflect/scala/reflect/api/package.scala +++ b/src/reflect/scala/reflect/api/package.scala @@ -2,211 +2,13 @@ package scala.reflect import scala.reflect.api.{Universe => ApiUniverse} -/** The Scala reflection API. +/** The Scala reflection API (located at scala-reflect.jar). * - * === Universes === - * - * Standard reflection interfaces and implementations are all contained in the package scala-reflect.jar. - * This jar is needed for all operations involving either Java reflection or macro implementations. - * The two share a large set of operations, which are all abstracted out in the reflective core API in [[scala.reflect.api.Universe]]. - * This universe provides a fairly complete set of reflection operations that allow to query key Scala type relations such as membership or subtyping. - * - * [[scala.reflect.api.Universe]] has two specialized sub-universes. [[scala.reflect.api.JavaUniverse]] adds operations that link symbols and types - * to the underlying classes and runtime values of a JVM. [[scala.reflect.macros.Universe]] adds operations which allow macros to access selected - * compiler data structures and operations. - * - * The main implementation object of scala-reflect.jar is named [[scala.reflect.runtime.package#universe scala.reflect.runtime.universe]]. - * It is a global singleton, which serves as an entry point to runtime reflection. - * There is no analogous global singleton universe for macros. Instead, macros access the currently running compiler instance as their universe, - * accessible via [[scala.reflect.macros.Context#universe]]. - * - * === Mirrors === - * - * Each universe has one or more mirrors. A mirror defines a hierarchy of symbols starting with the root package - * `_root_` and provides methods to locate and define classes and singleton objects in that hierarchy. - * Mirrors for runtime reflection also provide operations to reflect on runtime instances. - * - * All universes have one root mirror each, available in the `rootMirror` field. - * This mirror contains standard Scala classes and types - * such as `Any`, `AnyRef`, `AnyVal`, `Nothing`, `Null`, and all classes loaded from scala-library. - * The root package of the root mirror contains the root packages of all other mirrors as members. - * - * In a Java universe each mirror is associated with a classloader. This reflects the fact that multiple classes - * with the same name can exist in a JVM instance, where each class is loaded by a different classloader. - * To model this behavior, each JVM classloader is associated with a mirror, and each mirror contains its own - * hierarchy of packages and classes. However, the same class may also exist in several different classloaders - * and mirrors because classloaders can delegate to each other. This is modelled by one level of indirection: - * several packages in different mirrors can link to the same class. - * - * The main access point to mirrors in runtime reflection is [[scala.reflect.runtime.package#currentMirror]], - * which gives a JVM reflection mirror that corresponds to the current lexical context. - * `currentMirror` is typically equivalent to `universe.runtimeMirror(getClass.getClassLoader)` invoked at the call site. - * Macro universe is not based on classloaders, therefore it has only one mirror that corresponds to the compiler classpath, - * accessible via [[scala.reflect.macros.Context#mirror]]. - * - * === Toolboxes === - * - * Along with runtime Java universe [[scala.reflect.api.Universe]] and compile-time macro universe [[scala.reflect.macros.Universe]], - * reflection API also includes a runtime compiler universe implemented in `scala.tools.reflect`. One interacts with such universes - * via toolboxes, instances of `scala.tools.reflect.ToolBox` declared in scala-compiler.jar. - * - * After importing the `scala.tools.reflect.ToolBox` implicit conversion, runtime reflection mirrors gain the `mkToolBox` method - * that lets one create runtime compiler instances, optionally providing custom `options` string and a custom `frontEnd` that determines - * how to process warnings and errors emitted by the compilers. Toolboxes have such methods as `parse`, `typeCheck`, `inferImplicitValue`, `compile` and `eval`. - * - * === Known issues === + * Using Scala reflection requires understanding of a couple of basic concepts like Symbols, Types, Mirror and Universes. + * @see [[http://docs.scala-lang.org/overviews/reflection/overview.html]]. * * In Scala 2.10.0, reflection API and its implementation have 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 known issues. Here are some useful links: - * - [[https://issues.scala-lang.org/secure/IssueNavigator.jspa?mode=hide&requestId=10908 Known issues in reflection and macros]] - * - [[http://stackoverflow.com/questions/tagged/scala+reflection Questions tagged "scala" and "reflection" at Stack Overflow]] - * - * === Using runtime reflection === - * - * Suppose we want to invoke the `head` method on `List(1, 2)`. This can be done in four steps, which include: - * 1) setting up the environment, 2) getting to a symbol that represents `head`, 3) creating - * a method mirror for `head`, 4) invoking the method mirror. - * - * === Step 1: Setting up the environment === - * - * To do anything with reflection one needs to decide on a universe. The universe of choice for - * runtime reflection is [[scala.reflect.runtime.package#universe scala.reflect.runtime.universe]]. - * A commonplace idiom is to do a blanket import `import scala.reflect.runtime.universe._` to get - * access to all types and methods declared inside the universe. - * - * {{{ - * scala> import scala.reflect.runtime.universe._ - * import scala.reflect.runtime.universe._ - * }}} - * - * The next step is creating a mirror. On JVM mirrors are in one-to-one correspondence with classloaders. - * Another common idiom is to create a mirror from `getClass.getClassLoader`, the classloader of the - * current class. In most cases that will do, but if the structure of classloaders in your application - * is more complex than that, adjust accordingly. - * - * {{{ - * scala> val cm = runtimeMirror(getClass.getClassLoader) - * cm: reflect.runtime.universe.Mirror = JavaMirror with of type - * class scala.tools.nsc.interpreter.IMain$TranslatingClassLoader with classpath [(memory)] - * and parent being of type class scala.tools.nsc.util.ScalaClassLoader$ - * URLClassLoader with classpath [file:/c:/PROGRA~1/Java/JDK/jre/lib/resources.jar... - * }}} - * - * === Step 2: Getting to a symbol that represents `head` === - * - * We start with obtaining a type of `List` to get to the `head` symbol that represents the given method. - * There are three ways of doing that. - * - * The best way is to write `typeOf[List[Int]]`, which is applicable when the type - * of the value being inspected is known in advance, and which gives the exact information about the type. - * When the type is dynamic, we have to first obtain a Java class and then convert it to a Scala type, - * e.g. `cm.runtimeClass(list.getClass).toType`. Unfortunately then the information about the type - * suffers from erasure. - * - * {{{ - * scala> typeOf[List[Int]] - * res0: reflect.runtime.universe.Type = scala.List[Int] - * - * scala> cm.classSymbol(List(1, 2).getClass).toType - * res1: reflect.runtime.universe.Type = scala.collection.immutable.::[B] - * }}} - * - * A compromise solution, which allows to preserve the exact type information, involves `TypeTag` - * context bounds. If the value being inspected is an argument of a function, then we can make - * the corresponding parameter generic and annotated the introduced type parameter with a type tag. - * After we do that, the compiler will preserve exact types of arguments passed to a function, - * available via `typeOf`. - * - * {{{ - * scala> def invokeHead(x: Any): Any = { - * | // type of x is unknown, the best we can do is to approximate - * | println(cm.classSymbol(x.getClass).toType) - * | } - * invokeHead: (x: Any)Any - * - * scala> invokeHead(List(1, 2)) - * scala.collection.immutable.::[B] - * - * scala> invokeHead(List("x")) - * scala.collection.immutable.::[B] - * - * scala> def invokeHead[T: TypeTag](x: T): Any = { - * | // type of x is preserved by the compiler - * | println(typeOf[T]) - * | } - * invokeHead: [T](x: T)(implicit evidence$1: reflect.runtime.universe.TypeTag[T])Any - * - * scala> invokeHead(List(1, 2)) - * List[Int] - * - * scala> invokeHead(List("x")) - * List[java.lang.String] - * }}} - * - * Having a type at hand it is straightforward to traverse its members and obtain a symbol - * that represents `head`. - * - * {{{ - * scala> val head = typeOf[List[Int]].member("head": TermName).asMethod - * head: reflect.runtime.universe.MethodSymbol = method head - * }}} - * - * Note the `asMethod` cast following the invocation of `member`. In Scala reflection symbol-returning methods - * don't raise exceptions, but rather produce `NoSymbol`, a special singleton, which is a null object for symbols. - * Therefore to use such APIs one has to first check whether a callee returned a valid symbol and, if yes, then perform - * a cast using one of the `asTerm`, `asMethod`, `asModule`, `asType` or `asClass` methods. - * - * Also be careful with overloaded methods, which are represented as instances of `TermSymbol`, not `MethodSymbol`, - * with multiple `alternatives` of type `MethodSymbol` that have to be resolved manually. This and other gotchas with - * symbol loading are discussed on [[scala.reflect.api.Symbols the documentation page about symbols]]. - * - * === Step 3: Creating a method mirror for `head` === - * - * In Scala reflection, all reflective invocations go through mirrors created with `reflectXXX` methods. - * For example, to get a singleton instance of an `object`, one needs to reflect a `ModuleSymbol` to obtain - * a `ModuleMirror`, which provides the `instance` method. - * - * In our case we need to reflect an instance being processed, producing an `InstanceMirror`, then reflect - * a method symbol loaded during the previous step, producing a `MethodMirror`. Finally, method mirrors - * provide the `apply` method that performs reflective invocations. - * - * {{{ - * scala> val im = cm.reflect(List(1, 2)) - * im: reflect.runtime.universe.InstanceMirror = instance mirror for List(1, 2) - * - * scala> val mm = im.reflectMethod(head) - * mm: reflect.runtime.universe.MethodMirror = method mirror for - * scala.collection.IterableLike.head: A (bound to List(1, 2)) - * }}} - * - * === Step 4: Invoking the method mirror === - * - * The final step is straightforward. Reflective invocation of a method is as simple as calling - * the `apply` method of a `MethodMirror`: - * - * {{{ - * scala> mm() - * res1 @ 758f3dae: Any = 1 - * }}} - * - * === Conclusion === - * - * As specified in the documentation of traits declared in [[scala.reflect.api.Mirrors]], - * in a similar fashion (by using `reflectXXX` methods), it is possible to: - * - Get and set field values - * - Instantiate classes - * - Obtain singleton instances of objects - * - * However there's much more to Scala reflection, with examples on other documentation pages answering the following questions: - * - [[scala.reflect.api.Symbols How to get a Symbol that corresponds to a given definition?]] - * - [[scala.reflect.api.Types How to get a Type of some Scala code?]] - * - [[scala.reflect.api.Trees How to get a Tree that corresponds to some Scala code?]] - * - [[scala.reflect.api.Trees How to parse a string into a Tree?]] - * - [[scala.reflect.api.Trees How to compile or evaluate a Tree?]] - * - [[scala.reflect.api.Annotations How to get Java and/or Scala annotations attached to a given definition?]] - * - [[scala.reflect.api.Printers How to inspect internal structure of reflection artifacts?]] - * - [[scala.reflect.api.Importers How to move reflection artifacts from one universe to another?]] - * - [[scala.reflect.macros.package How to use compile-time reflection in macros?]] + * in binary- and source-incompatible manner in 2.10.1. This also means that the implementation has known issues */ package object api { -- cgit v1.2.3