为什么在 Hack 中,类范围的上限约束不能是协变的,而下界约束是逆变的?



无论左侧参数的方差如何,以下声明中对TaTb施加的约束都无法通过类型检查:

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开始,通过这次提交,限制已经放宽,允许对类类型参数进行子类型化!该承诺还指出,微软的这篇论文证明了其合理性。

相关内容

  • 没有找到相关文章

最新更新