Что делает это требование класса циклическим определением класса?

Проверщик типов считает это требование класса интерфейсом 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 было бы похоже на множественное ограничение, и без этой загадочной циклической проблемы это было бы аккуратным решением.

Другая естественная альтернатива для принимающего класса - добавить параметр в свой список параметров как TComparable as Comparable<TComparable>, но это побеждает принцип не заботиться о TComparable,

1 ответ

Ну, я не эксперт, но сообщение мне кажется ясным: определение является циклическим, потому что Derived использования IBase а также IBase Рекомендации Derived, Согласно документации:

Требуется расширяет, следует понимать буквально. Класс должен расширять необходимый класс; таким образом, фактический требуемый класс не соответствует этому требованию. Это позволяет избежать некоторых тонких циклических зависимостей при проверке требований.

Я думаю, что для этого нужно указать требование к классу-предку и реализовать интерфейс в неабстрактном производном классе (ах). Или, может быть, просто реализовать compare как обычный метод в классе предков, вместо использования черты.

Другие вопросы по тегам