When reading some articles about Scala, I found some examples with a curious syntax, which I might understand incorrectly
class Child[C <: Child[C]] {
some_name : C => // here, what does it mean?
var roomie : Option[C] = None
def roomWith(aChild : C)= {
roomie = Some(aChild)
aChild.roomie = Some(this)
}
}
class Boy extends Child[Boy]
I found similar examples with traits.
Does it mean that I declare this
object in a class scope to by type of C
?
It is a self type annotation.
This means that class Child
must be of type C
, i.e., creates inheritance dependencies which must satisfied for a given class.
A small example:
scala> trait Baz
defined trait Baz
scala> class Foo {
| self:Baz =>
| }
defined class Foo
scala> val a = new Foo
<console>:9: error: class Foo cannot be instantiated because it does not conform to its self-type Foo with Baz
val a = new Foo
^
scala> val a = new Foo with Baz
a: Foo with Baz = $anon$1@199de181
scala> class Bar extends Foo with Baz
defined class Bar
In this case Foo
is required to also be a Baz
.
Satisfying that requirement, a Foo
instance can be created.
Also, defining a new class (in this case Bar
) there is also the requirement of it being Baz
as well.
See: http://www.scala-lang.org/node/124
One very useful application of self types is a less verbose implementation of the CRTP ( http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern ), e.g.
abstract class Base[Sub] {
self:Sub =>
def add(s:Sub) : Sub
}
case class Vec3(x:Double,y:Double,z:Double) extends Base[Vec3] {
def add(that:Vec3) = Vec3(this.x+that.x, this.y+that.y, this.z+that.z)
}
Attempts to "cheat" with the inheritance won't work:
class Foo extends Base[Vec3] {
add(v:Vec3) = v
}
//error: illegal inheritance;
//self-type Foo does not conform to Base[Vec3]'s selftype Base[Vec3] with Vec3
// class Foo extends Base[Vec3] {
In addition to the inheritance requirement in JaimeJorge's response, self types can be used to give the outer instance a name if you want to refer to it from an inner class:
scala> class Company(name: String) {
| company =>
| class Department(name: String) {
| override def toString = "Department "+ name +" of "+ company.name
| }
| }
defined class Company
scala> val c = new Company("ACME")
c: Company = Company@56a57bb2
scala> val d = new c.Department("Marketing")
d: c.Department = Department Marketing of ACME
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With