Скала: незаконное наследование;тип self Y не соответствует типу self self X - PullRequest
14 голосов
/ 11 сентября 2011

У меня есть черта, которая принимает параметр типа, и я хочу сказать, что объекты, реализующие эту черту, также будут соответствовать этому параметру типа (с использованием обобщений для совместимости с Java)

Следующий код:

trait HandleOwner[SELF <: HandleOwner[SELF]] {
self : SELF =>
    // ...
    def handle: Handle[SELF]
}

trait Common[SELF <: Common[SELF]]  extends HandleOwner[SELF] {
    // ...
}

Дает мне следующую ошибку:

illegal inheritance;  self-type test.Common[SELF] does not conform to
test.HandleOwner[SELF]'s selftype SELF

Если я изменяю Общий на:

trait Common[SELF <: Common[SELF]]  extends HandleOwner[SELF] {
self : SELF =>
    // ...
}

Тогда ошибка исчезает.

Почему я должен повторять одно и то же объявление для каждого неконкретного типа?Если бы у меня был базовый класс, и я сказал бы «extends Comparable», мне не нужно повторять «extends Comparable» в каждом производном типе, пока конкретные классы реализуют метод compareTo.Я думаю, что здесь должно быть то же самое.Я просто говорю, что тип, расширяющий HandleOwner , будет также SELF, и компилятор должен просто принять это и принять это во внимание, не требуя, чтобы каждый не конкретный подтип повторял одно и то же снова.

Я делаю это, чтобы избежать необходимости использовать приведение классов, но я буду буквально расширять каждый класс этой чертой, и я не вижу, что мне придется повторять эти объявления сотнями или даже тысячамираз!

1 Ответ

14 голосов
/ 11 сентября 2011

Тип Self больше похож на общие ограничения, чем на наследование.При class C[A <: B] ограничение должно повторяться все время в подклассах: class D[A <: B] extends C[A].Ограничение должно повторяться до тех пор, пока оно не будет выполнено, то есть до тех пор, пока вы не выберете фактический тип параметра, который действительно удовлетворяет <: B.То же самое для самостоятельного типа.Запись self: A => не делает ваш тип расширенным A.Это гарантирует, что в конечном итоге его нужно будет смешать с A, прежде чем он будет фактически создан.

Напротив, когда вы расширяете Comparable, вы сделали свой класс Comparable, не устанавливая ограничения на будущее.Но тот факт, что вам нужно реализовать compareTo, все еще должен повторяться вместе с abstract, пока вы его не реализуете.

Конечно, компилятор может обойтись без повторения <: B, self: A => и abstract, информация для него доступна.Это выбор дизайнера языка.По крайней мере, повторение self: A => ничем не отличается от правил повсюду.

...