是什么让这个类要求成为循环类定义?

时间:2017-05-12 04:58:40

标签: constraints hacklang cyclic

类型检查器认为接口IBase的这个类要求是循环的:

<?hh // strict
interface IBase {
    require extends Derived;
}
class Derived implements IBase {}
// Cyclic class definition : IBase Derived  (Typing[4013])

根据我的理解,约束只会阻止来自implements IBase而没有extends Derived的所有后代。我有没有看到这个漏洞?

我为什么关心?

我对想要与其自身或其子类型的其他实例进行比较的界面感兴趣。

<?hh // strict
interface Comparable<-T as Comparable<T>> {
    require extends ArtificialCeiling;
    public function compare(T $comparee): bool;
}
abstract class ArtificialCeiling implements Comparable<ArtificialCeiling> {
    abstract public function compare(ArtificialCeiling $comparee): bool;
}

this不是这里的答案,因为this在逆变位置不发声,especially in interfaces

假设现在我们想要接受并存储 Comparable的包装,但我们并不关心它在Comparable的哪种类型。通常情况下,我们只是使用上限进行参数化,如果不受约束,则为mixed

问题在于Comparable的上限永远是Comparable<Comparable<Comparable<...,但是我没有足够的耐力为永恒打字。如果没有像Scala这样的存在类型或像TComparable as Comparable & ArtificialCeiling这样的多个约束,我们就必须采用不太明显的东西。 require extends ArtificialCeiling就像一个多重约束,没有这个神秘的循环问题,它将是一个整洁的修复。

另一个自然的替代方法是让接受类将参数作为TComparable as Comparable<TComparable>附加到自己的参数列表中,但这违背了不关心TComparable的原则。

1 个答案:

答案 0 :(得分:1)

嗯,我不是专家,但这个消息对我来说似乎很清楚: 该定义是循环的,因为Derived使用IBaseIBase引用Derived。 根据{{​​3}}:

  

要求延伸应按字面意思。班级必须扩展   必修课;因此,实际所需的课程不符合要求   需求。这是为了避免一些微妙的循环依赖   检查要求。

我认为要采用的方法是指定祖先类的要求,并在非抽象派生类中实现接口。或者也许只是在祖先类中实现compare作为普通方法,而不是使用特征。