Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a "SELF" type in scala that represents the current type?

I'm learning Scala and there is a thing that I can't find out about the language:

Some time ago I was very comfortable programming in Lisaac, and in Lisaac I could write a class PERSON with a slot list:ARRAY[SELF], which was equivalent to have list:ARRAY[PERSON], since SELF is the type of the object where that slot is.

But by using SELF, if I write a second class STUDENT that inherits from PERSON, then STUDENT would inherit that slot changing SELF for STUDENT, so STUDENT would have a list of STUDENT instead of PERSON.

Can that be done in Scala? I can´t find out anything about that.

Thanks!

like image 791
Damian Avatar asked Oct 19 '09 03:10

Damian


1 Answers

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()
like image 154
Blaisorblade Avatar answered Oct 07 '22 00:10

Blaisorblade