Quando viene @uncheckedVariance necessaria a Scala, e perché è usato in GenericTraversableTemplate?
-
20-09-2019 - |
Domanda
@uncheckedVariance
può essere utilizzato per colmare il divario tra sito dichiarazione annotazioni di varianza di Scala e generici invarianti di Java.
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
Questo dice che java.util.Comparator è naturalmente contra-variante, che è il parametro di tipo T
appare nei parametri e mai in un tipo di ritorno.
Questo pone la domanda: perché si usa anche nella biblioteca collezioni Scala che non si estende da interfacce Java
trait GenericTraversableTemplate[+A, +CC[X] <: Traversable[X]] extends HasNewBuilder[A, CC[A] @uncheckedVariance]
Quali sono gli usi validi per questa annotazione?
Soluzione
Il problema è che GenericTraversableTemplate viene utilizzato due volte: una volta per le collezioni mutabili (dove il suo parametro di tipo dovrebbe essere invariante), e una volta per le collezioni immutabili (dove covarianza è invariabilmente re)
.typechecks di GenericTraversableTemplate assumendo sia covarianza o invarianza del parametro Un tipo. Tuttavia, quando abbiamo ereditato in un tratto mutevole, dobbiamo raccogliere invarianza. Al contrario, ci piacerebbe covarianza in una sottoclasse immutabile.
Poiché non possiamo astratta sull'annotazione varianza (ancora ;-)) in GenericTraversableTemplate, così che abbiamo potuto istanziata ad uno dei due a seconda della sottoclasse, dobbiamo ricorrere a getto (@uncheckVariance è essenzialmente una sorta -cast). Per ulteriori approfondimenti, vi consiglio la mia tesi di laurea (scusate ;-)) o il nostro recente carta bitrot
Altri suggerimenti
Nella mia tesi ho descritto un calcolo, Scalina, che ha limiti e le annotazioni di varianza come parte del linguaggio genere (una versione precedente è disponibile anche come carta officina ). La rilevanza di questa discussione è il prossimo passo che voglio prendere nello sviluppo di questo calcolo: costruire un altro strato in cima a quello in modo che possiate astratto su limiti (facile) e le annotazioni di varianza (mi fa girare la testa). In realtà, si sarebbe non solo virata 1 strato supplementare in là, ma piuttosto allargare la costrutti polimorfismo in modo da lavorare a tutti i livelli, e rendere il vostro "attributi" (limiti, annotazioni di varianza, argomenti impliciti richiesti, ...) in tipi regolari con i generi speciali, che sono tutti soggetti all'astrazione.
Gli "attributi sono tipi" idea è spiegato bene dal Edsko de Vries nel contesto dei tipi di unicità.
Unicità Digitando semplificato , Edsko de Vries, Rinus Plasmeijer, e David Abrahamson. In Olaf Chitil, Zoltán Horváth e Viktória Zsók (Eds.): IFL 2007 LNCS 5083, pp. 201-218, 2008.
Premessa: Vi presentiamo un tipo di unicità sistema che è più semplice che sia sistema di unicità è pulito e il Sistema abbiamo proposto in precedenza. Il nuovo Sistema tipo è semplice da implementare e aggiungere al già esistente compilatori, e possono facilmente essere estese con funzioni avanzate come più alti Tipi di rango e impredicativity. Noi descrivere la nostra implementazione in Morrow, un linguaggio funzionale sperimentale con entrambe queste caratteristiche. Infine, dimostrare solidità del tipo nucleo sistema rispetto al Call-by-necessità lambda calcolo.
Ho trovato un altro momento in cui viene utilizzato @uncheckedVariance - il metodo di sintesi che restituisce il valore predefinito per un parametro di un tipo astratto:
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();
()
}
}
}
}