Reputation: 321
Consider the following class definitions:
class Person[+T <: Person[T]]
class Student() extends Person[Student]
class Professor() extends Person[Professor]
I would like a list with a student and a professor:
val persons = List(new Student(), new Professor())
But this fails to compile with the following error:
type arguments [Person[Person[Any]]] do not conform to class Person's type parameter bounds [+T <: Person[T]]
Thanks to Daniel C. Sobral's answer to my related previous question How to define case classes with members with unbound type parameters? I know an existential type would do the trick here. This compiles:
val persons = List[Person[T] forSome {type T <: Person[T]}](new Student(), new Professor())
The problem is caused by the upper-bound <: Person[T]
in the type parameter of the class Person's declaration. Removing the upper-bound lets the compiler infer a type parameter for the list which makes it compile: List[Person[Person[Person[Any]]]]
as far as I can see.
Questions
Upvotes: 1
Views: 149
Reputation: 597
I believe you've mentioned a possible alternative yourself in your second comment
val persons = List[Person[_]](new Student(), new Professor())
But from my understanding, the idiomatic way in Scala for doing things like this is to use a type declaration in Person and have it defined in Student and Professor:
trait Person {
type PersonImpl <: Person
def colleagues: Seq[PersonImpl]
}
class Student extends Person {
type PersonImpl = Student
def colleagues = Seq(this)
}
class Professor extends Person {
type PersonImpl = Professor
def colleagues = Seq(this)
}
val persons = List(new Student, new Professor)
Martin Odersky also mentioned in scala-language, that he's thinking about unifying type parameters and abstract type members.
Dependent on your actual use case, the simplest solution may be to rely on method overriding:
trait Person {
def colleagues: Seq[Person]
}
class Student extends Person {
def colleagues: Seq[Student] = Seq(this)
}
class Professor extends Person {
def colleagues: Seq[Professor] = Seq(this)
}
val persons = List(new Student, new Professor)
Upvotes: 1