Wann wird @Utcheckedvarianz in Scala benötigt und warum wird es in GenericTraversableStemplate verwendet?

StackOverflow https://stackoverflow.com/questions/2454281

Frage

@uncheckedVariance Kann verwendet werden, um die Kluft zwischen den Varianzanmerkungen der Scala -Deklaration und den invarianten Generika von Java zu schließen.

scala> import java.util.Comparator    
import java.util.Comparator

scala> trait Foo[T] extends Comparator[T]
defined trait Foo

scala> trait Foo[-T] extends Comparator[T]     
<console>:5: error: contravariant type T occurs in invariant position in type [-T]java.lang.Object with java.util.Comparator[T] of trait Foo
       trait Foo[-T] extends Comparator[T]
             ^

scala> import annotation.unchecked._    
import annotation.unchecked._

scala> trait Foo[-T] extends Comparator[T @uncheckedVariance]    
defined trait Foo

Dies besagt, dass Java.util.comParator von Natur aus kontra-varianten ist, das ist der Typparameter T erscheint in Parametern und nie in einem Rückgabetyp.

Dies wirft die Frage auf: Warum wird es auch in der Scala -Sammlungsbibliothek verwendet, die sich nicht von Java -Schnittstellen erstreckt?

trait GenericTraversableTemplate[+A, +CC[X] <: Traversable[X]] extends HasNewBuilder[A, CC[A] @uncheckedVariance]

Was sind die gültigen Verwendungen für diese Annotation?

War es hilfreich?

Lösung

Das Problem ist, dass generictraversableStemplate zweimal verwendet wird: einmal für veränderliche Sammlungen (wobei sein Typparameter invariant sein sollte) und einmal für unveränderliche Sammlungen (wo die Kovarianz ausnahmslos König ist).

GenericTraversableStemplate -Tazipiten übernehmen entweder Kovarianz oder Invarianz für den A -Typ -Parameter. Wenn wir es jedoch in einem veränderlichen Merkmal erben, müssen wir Invarianz auswählen. Umgekehrt möchten wir Kovarianz in einer unveränderlichen Unterklasse.

Da wir die Varianzannotation (noch ;-)) in genericTraversableStemplate nicht abstrakt abstrahieren können, so dass wir sie je nach Unterklasse auf beide hätten entwickelt haben können, müssen wir auf das Casting zurückgreifen (@Utcheckvarianz ist im Wesentlichen ein Art-Cast). . Zum weiteren Lesen empfehle ich meine Dissertation (sorry ;-)) oder unsere aktuelle Bitrotpapier

Andere Tipps

In meiner These beschreibe ich einen Kalkül, Scalina, der Annotationen von Grenzen und Varianz als Teil der Art Sprache hat (eine frühere Version ist auch als verfügbar Workshop -Papier). Die Relevanz für diese Diskussion ist der nächste Schritt, den ich bei der Entwicklung dieses Kalküls machen möchte: Erstellen Sie eine weitere Ebene darüber, damit Sie über Grenzen (einfach) und Varianzanmerkungen abstrahieren können (was meinen Kopf dreht). Tatsächlich würden Sie dort nicht nur 1 zusätzliche Schicht anschließen, sondern Ihre Polymorphismuskonstrukte vieler zur Verfügung stellen, damit sie auf allen Ebenen funktionieren und Ihre "Attribute" (Grenzen, Varianzanmerkungen, erforderliche implizite Argumente, ...) in reguläre Typen machen mit besonderen Arten, die alle einer Abstraktion unterliegen.

Die Idee "Attribute sind Typen" wird von Edsko de Vries im Kontext von Einzigartigkeitstypen gut erklärt.

Einzigartigkeitstypisierung vereinfacht, Edsko de Vries, Rinus Plasmeijer und David Abrahamson. In Olaf Chitil, Zoltán Horváth und Viktória Zsók (Hrsg.): IFL 2007, LNCS 5083, S. 201-218, 2008.

Zusammenfassung: Wir präsentieren ein Einzigartigkeitssystem, das einfacher ist als das Einzigartigkeitssystem von Clean und das zuvor vorgeschlagene System. Das neue Typ -System ist unkompliziert, um vorhandene Compiler zu implementieren und zu erweitern, und kann problemlos mit erweiterten Funktionen wie höheren Rangtypen und beeindruckenden Eingriffe erweitert werden. Wir beschreiben unsere Implementierung in Morrow, eine experimentelle funktionale Sprache mit beiden Merkmalen. Schließlich beweisen wir die Ton des Kerntypsystems in Bezug auf den Call-by-Need-Lambda-Kalkül.

Ich habe eine andere Zeit gefunden, in der @Utcheckedvarianz verwendet wird - die synthetische Methode, die den Standardwert für einen Parameter eines abstrakten Typs zurückgibt:

M:\>scala -Xprint:typer -e "class C { def p[T >: Null](t: T = null) = t }"
[[syntax trees at end of typer]]// Scala source: (virtual file)
package <empty> {
  final object Main extends java.lang.Object with ScalaObject {
    def this(): object Main = {
      Main.super.this();
      ()
    };
    def main(argv: Array[String]): Unit = {
      val args: Array[String] = argv;
      {
        final class $anon extends scala.AnyRef {
          def this(): anonymous class $anon = {
            $anon.super.this();
            ()
          };
          class C extends java.lang.Object with ScalaObject {
            <synthetic> def p$default$1[T >: Null <: Any]: Null @scala.annotation.unchecked.uncheckedVariance = null;
            def this(): this.C = {
              C.super.this();
              ()
            };
            def p[T >: Null <: Any](t: T = null): T = t
          }
        };
        {
          new $anon();
          ()
        }
      }
    }
  }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top