There is an idiom for this, and it is used extensively in the collections framework (in all the *Like classes, e.g TraversableLike).
You need to add the self-type as a type parameter (like possible in C++ with the CRTP) of the superclass:
trait Person[+Self] {
this: Self => //Declare that any concrete subclass must implement Self; therefore, this can be used with type Self.
//val list: Array[Self] //Not sure that this will work so easily, for the same reason new T[] does not work in Java.
val list = Seq[Self]() //No problem here; Array is really special.
}
After defining this class, we can try defining subclasses in the interpreter:
scala> class Student extends Person[Student]
defined class Student
scala> (new Student).list
res0: Seq[Student] = List() //Note the result type
scala> class Student2 extends Person[Student] //Note the mistake
<console>:9: error: illegal inheritance;
self-type Student2 does not conform to Person[Student]'s selftype Person[Student] with Student
class Student2 extends Person[Student]
A mistake which is not prevented is having this definition, where Self is not redefined:
scala> class SpecStudent extends Student
defined class SpecStudent
Thanks to the + in front of Self, which makes it a covariant type parameter (I'm not explaining what that is), this however is at least possible:
scala> class SpecStudentCorrect extends Student with Person[SpecStudentCorrect]
scala> (new SpecStudentCorrect).list
(new SpecStudentCorrect).list
res1: Seq[SpecStudentCorrect] = List()
answered 2012-01-31T10:13:58.857