タイプチェッカーは、インターフェースによるこのクラス要件を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
のラッパーを受け入れて保存Comparable
したいが、それがどのタイプを持ち歩いているかは気にしないとComparable
します。通常、上限でパラメータ化するmixed
か、制約がない場合はパラメータ化します。
問題は、上限Comparable
がComparable<Comparable<Comparable<...
永遠であることですが、それを永遠に入力するスタミナがありません。Scala のような存在型や のような複数の制約がなければTComparable as Comparable & ArtificialCeiling
、あまり明白でない方法に頼る必要があります。require extends ArtificialCeiling
これは複数の制約のようなものであり、この不思議な循環問題がなければ、きちんとした修正になります。
もう 1 つの自然な代替方法は、受け入れクラスがパラメーターを として独自のパラメーター リストに追加することTComparable as Comparable<TComparable>
ですが、これは を気にしないという原則を無効にしTComparable
ます。