Unabhängig von der Varianz des Parameters auf der linken Seite, die platzierten Beschränkungen für Ta
und Tb
in der folgenden Erklärung versagt die typecheck:Warum können klassenübergreifende Obergrenzeneinschränkungen nicht kovariant sein und Untergrenzeneinschränkungen in Hack kontravariant sein?
class A<+TCov, -TCon, [±]Ta as TCov, [±]Tb super TCon> {
public function __construct(private Ta $ta, private Tb $tb) {}
// [various methods making use of Ta and Tb]
}
Es ist erwähnenswert, dass die leere Klassendeklaration Fehler nicht erhöhen, sondern sobald die Parameter beschränkt verwendet (eigene Varianzen in ansonsten gültigen Positionen angegeben) sind, hebt der typechecker einen der folgenden Schritte:
Illegal Verwendung von kovarianten Typparameter (Typing [4120]), ...
as
Constraints kontraIllegal Verwendung kontraTypParameter (Typing [4121]) sind ...
super
Constraints sind kovarianten
mit Bezug auf den Parameter auf der rechten Seite der Einschränkungs.
Ich kann mehr verstehen, warum generische Methoden Probleme darstellen. Die Verletzung Positionen sind ziemlich offensichtlich, und unter Verwendung der Argumente in Positionen, die Varianz ihrer Zwänge anpassen, sind unmöglich:
class A<+TCov, -TCon> {
public function cov_violate<T as TCov>(T $v): void {
// T can be cast to TCov and violate type if the original type is a subtype of T
}
public function con_violate<T super TCon>(): T {
// vice versa for the contravariant parameter
}
public function cov_impossible<T as TCov>(): T {
// how will we produce a T-typed value?
}
public function con_impossible<T super TCov>(T $v): void {
// what will we do with a T-typed value?
}
}
Aber was ist das Problem mit klassenweite Parameter? Für alle sechs fehlerhaften Beziehungen ({+|-| }T as +TCov
und {+|-| }T super -TCon
) kann ich mir kein Szenario ausdenken, in dem diese nicht typsicher wären. Meiner Meinung nach scheinen ihre Varianzen entweder ihre Casting-Richtung oder ihre Positionen ausreichend einzuschränken, um diese Beziehungen als sicher zu deklarieren.