[FIXED] Wie erstelle ich ein TypeTag manuell?

Ausgabe

Ich bin daran interessiert, ein TypeTag manuell zu erstellen (seit 2.10M5):

object X {
  import reflect.runtime.universe._
  def tt[A : TypeTag](a: A) = typeTag[A] // how to do this manually?
  val t = tt(List("")(_))
}

scalac -Xprint:typer <file>.scalaergibt sich

package <empty> {
  object X extends scala.AnyRef {
    def <init>(): X.type = {
      X.super.<init>();
      ()
    };
    import scala.reflect.runtime.`package`.universe._;
    def tt[A >: Nothing <: Any](a: A)(implicit evidence$1: reflect.runtime.universe.TypeTag[A]): reflect.runtime.universe.TypeTag[A] = scala.reflect.runtime.`package`.universe.typeTag[A](evidence$1);
    private[this] val t: reflect.runtime.universe.TypeTag[Int => String] = X.this.tt[Int => String](((x$1: Int) => immutable.this.List.apply[String]("").apply(x$1)))({
      val $u: reflect.runtime.universe.type = scala.this.reflect.runtime.`package`.universe;
      val $m: $u.Mirror = scala.this.reflect.runtime.`package`.universe.runtimeMirror(this.getClass().getClassLoader());
      $u.TypeTag.apply[Int => String]($m, {
        final class $typecreator1 extends TypeCreator {
          def <init>(): $typecreator1 = {
            $typecreator1.super.<init>();
            ()
          };
          def apply[U >: Nothing <: scala.reflect.base.Universe with Singleton]($m$untyped: scala.reflect.base.MirrorOf[U]): U#Type = {
            val $u: U = $m$untyped.universe;
            val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror];
            $u.TypeRef.apply($u.ThisType.apply($m.staticModule("scala").asModuleSymbol.moduleClass), $m.staticClass("scala.Function1"), scala.collection.immutable.List.apply[$u.Type]($m.staticClass("scala.Int").asTypeSymbol.asTypeConstructor, $m.staticClass("java.lang.String").asTypeSymbol.asTypeConstructor))
          }
        };
        new $typecreator1()
      })
    });
    <stable> <accessor> def t: reflect.runtime.universe.TypeTag[Int => String] = X.this.t
  }
}

Es scheint vollständig Compiler-Magie zu sein, da die Typen fest codiert sind. Gibt es trotzdem eine Möglichkeit, dies manuell zu tun?

Lösung

In M3 könnte man ganz einfach ein Typ-Tag erstellen, zB: TypeTag[Int](TypeRef(<scala package>, <symbol of scala.Int>, Nil)). Es bedeutete im Grunde, dass ein einmal erstellter Typ-Tag für immer an einen bestimmten Classloader gebunden ist (nämlich denjenigen, der zum Laden eines Symbols von scala.Int im obigen Beispiel verwendet wurde).

Damals war es in Ordnung, weil wir überlegten, dass wir einen Spiegel in einer Größe haben könnten, der für alle Classloader geeignet ist. Das war praktisch, weil Sie einfach schreiben konnten implicitly[TypeTag[T]]und der Compiler diesen globalen Spiegel verwenden würde, um einen von Ihnen angeforderten Typ zu instanziieren.

Leider haben wir später aufgrund von Feedback festgestellt, dass dies nicht funktionieren wird und dass wir mehrere Mirrors benötigen – jeder mit seinem eigenen Classloader.

Und dann wurde deutlich, dass Typ-Tags flexibel sein müssen, denn sobald Sie schreiben, dass implicitly[TypeTag[T]]der Compiler nicht genügend Informationen darüber hat, welchen Classloader Sie verwenden möchten. Grundsätzlich gab es zwei Alternativen: 1) Type-Tags pfadabhängig von Mirrors machen (so dass man gezwungen wäre, jedes Mal, wenn ein Type-Tag vom Compiler angefordert wird, explizit einen Mirror bereitzustellen), 2) Type-Tags in Type-Factories umwandeln, fähig sich in jedem Spiegel zu instanziieren. Um es kurz zu machen, die erste Option hat nicht funktioniert, also sind wir da, wo wir sind.

Daher müssen Typ-Tags derzeit auf ziemlich umständliche Weise erstellt werden, wie in https://github.com/scala/scala/blob/master/src/library/scala/reflect/base/TypeTags.scala#L143 beschrieben . Sie rufen eine im Companion definierte Factory-Methode auf TypeTagund geben zwei Argumente an: 1) einen Standard-Mirror, in dem das Type-Tag instanziiert wird, 2) eine Type-Factory, die ein Type-Tag in einem beliebigen Mirror instanziieren kann. Dies ist im Grunde das, was der Compiler in dem Ausdruck getan hat, den Sie oben angehängt haben.

Warum habe ich diesen Kreisverkehr angerufen? Denn um eine Typfabrik bereitzustellen, müssen Sie die Klasse manuell unterklassen scala.reflect.base.TypeFactory. Das ist eine unglückliche Einschränkung des Scala-Typsystems an der Grenze zwischen Funktion und abhängig typisierten Methoden.


Beantwortet von –
Eugene Burmako


Antwort geprüft von –
Dawn Plyler (FixError Volunteer)

0 Shares:
Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like