无论左侧参数的方差如何,以下声明中对Ta
和Tb
施加的约束都无法通过类型检查:
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]
}
值得注意的是,空类声明不会引发错误,但一旦使用了约束参数(在给定其自身方差的其他有效位置),类型检查器就会引发以下之一:
非法使用协变类型参数(键入[4120])。。。
as
约束是反变非法使用逆变类型参数(键入[4121])。。。
super
约束是协变
参照约束右侧的参数。
我更能理解为什么泛型方法会带来问题。违反立场是相当明显的,并且在与约束的方差相匹配的立场上使用自变量是不可能的:
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?
}
}
但是类范围参数的问题是什么?对于所有六个错误的关系({+|-| }T as +TCov
和{+|-| }T super -TCon
),我想不出一种情况下这些关系不会是类型安全的。在我看来,他们的差异似乎限制了他们的选角方向或立场,足以让宣布这些关系是安全的。
在提出这个问题时,我运行的是3.13.1,但幸运的是,从HHVM 3.14.4开始,通过这次提交,限制已经放宽,允许对类类型参数进行子类型化!该承诺还指出,微软的这篇论文证明了其合理性。