Scala: незаконное наследование; сам тип Y не соответствует X selftype SELF
У меня есть черта, которая принимает параметр типа, и я хочу сказать, что объекты, реализующие этот признак, также будут соответствовать этому параметру типа (используя generics для совместимости с 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] selftype SELF
Если я изменил Common на:
trait Common[SELF <: Common[SELF]] extends HandleOwner[SELF] {
self : SELF =>
// ...
}
Затем ошибка исчезает.
Почему я должен повторять одно и то же объявление в каждом небетоновом типе. Если бы у меня был базовый класс и я говорю "extends Comparable", мне не нужно повторять "extends Comparable" в каждом производном типе, если конкретные классы реализуют метод compareTo. Я думаю, что здесь должно быть одно и то же. Я просто говорю, что тип, расширяющий HandleOwner, также будет SELF, и компилятор должен просто принять его и принять его во внимание, не требуя, чтобы каждый небетонный подтип повторял то же самое снова.
Я делаю это, чтобы избежать использования класса, но я буду буквально расширять каждый класс из этой черты, и я не вижу, что мне придется повторять эти объявления сотни или даже тысячи раз!
Ответы
Ответ 1
Тип "Я" больше похож на общее ограничение, чем наследование. При class C[A <: B]
ограничение должно повторяться все время в подклассах: class D[A <: B] extends C[A]
. Ограничение должно повторяться до тех пор, пока оно не будет выполнено, то есть пока вы не выбрали фактический тип параметра, который действительно удовлетворяет <: B
. То же самое для типа self. Написание self: A =>
не приводит к расширению вашего типа A
. Это гарантирует, что в конечном итоге его нужно будет смешивать с A до того, как он будет фактически создан.
Напротив, когда вы расширяете Comparable
, вы сделали свой класс a Comparable
, а не ограничиваете его позже. Но тот факт, что вам нужно реализовать compareTo
, все равно нужно повторять вместе с abstract
, пока вы его не реализуете.
Конечно, компилятор мог обойтись без повторения <: B
, self: A =>
и abstract
, информация доступна для него. Это выбор языка. По крайней мере, повторение self: A =>
не отличается от правил везде.