define method to return type of class extending it
I'd like to be able to do something like this:
trait A {
def f(): ???_THE_EXTENDING CLASS
}
class C extends A {
def f() = self
}
class D extends A {
def f() = new D
}
class Z extends D {
def f() = new Z
}
And the following would not compile, given the above code
class Bad1 extends A {
def f() = "unrelated string"
}
class Bad2 extends A {
def f() = new C // this means that you can't just define a type parameter on
// A like A[T <: A] with f() defined as f: T
}
class Bad3 extends D // f() now doesn't return the correct type
Is there a name for this kind of relationship? And how is it annotated/implemented in Scala?
Edit
The following sort of works, as you can see:
scala> trait A {
| def f: this.type
| }
defined trait A
scala> class C extends A {
| def f = this
| }
defined class C
scala&开发者_运维问答gt; class D extends A {
| def f = new D
| }
<console>:7: error: type mismatch;
found : D
required: D.this.type
def f = new D
^
Is there a way to get around that?
Edit 2
Using the second system, I can do this, which is good up to the definition of class D:
scala> trait A[T <: A[T]] { def f(): T }
defined trait A
// OR
scala> trait A[T <: A[T]] { self: T =>
| def f(): T
| }
scala> class C extends A[C] { def f() = new C }
defined class C
scala> class D extends C
defined class D
scala> (new D).f
res0: C = C@465fadce
I'm afraid there is no possibility to know what is the extended class from the extending class.
The closest to what you'd like to have is something similar to Curiously Recurring Template Pattern (CRTP) well known from C++.
trait A[T <: A[T]] {
def f(): T;
}
class C extends A[C] {
def f() = new C
}
class D extends A[D] {
def f() = new D
}
One thing that you can do, is to return type this.type
:
trait A {
def f(): this.type
}
class C extends A {
def f() = this
}
class D extends A {
def f() = this
}
class Z extends D {
override def f() = this
def x = "x"
}
println((new Z).f().x)
This can be useful for builders.
Here is another possible solution. It's combination of self type + type parameter:
trait A[T <: A[T]] { self: T =>
def f(): T
}
class Z extends A[Z] {
override def f() = new Z
def x = "x"
}
println((new Z).f().x)
Here you can find more info about this solution:
scala self-type: value is not a member error
精彩评论