Reputation: 12852
Given a trait T
trait T {
def v: Int
def +(t: T): T
}
the following class A
case class A(v: Int) extends T {
def +(a: A) = A(v + a.v)
}
is not a valid subtype of T
. The implementation of A.+
is too restrictive, because it only accepts elements of type A
whereas the signature of T.+
requires all implementations to be able to accept objects of type T
and not just objects of type A
.
So far, so reasonable.
If I'd like to allow implementations of T
to be that restrictive I can modify the declarations of T
and A
as follows
trait T[This <: T[This]] {
def v: Int
def +(t: This): This
}
case class A(v: Int) extends T[A] {
def +(a: A) = A(v + a.v)
}
which obviously blows up the type signature.
Is there another way to declare that implementations of T
only need to be compatible with objects of their own type?
1st EDIT In reply to Landei's answer below:
While self-types indeed shorten the current signature they don't shorten other signatures where T
occurs, e.g.
trait C[D <: T[D], S] { self: S =>
def +(perm: D): S
def matches(other: S): Boolean
}
Upvotes: 2
Views: 197
Reputation: 12158
You can do it with type members. I don't know what brand of "short" you're after here exactly. There is some redundancy, but on the other hand no type parameters passes big bracket savings on to you.
trait TT {
type This <: TT
def v: Int
def +(t: This): This
}
case class AA(v: Int) extends TT {
type This = AA
def +(a: This) = AA(v + a.v)
}
Upvotes: 1
Reputation: 54574
You can use self-types:
trait T[S] {
self:S =>
def v: Int
def +(t: S): S
}
case class A(v: Int) extends T[A] {
def +(a: A) = A(v + a.v)
}
Upvotes: 1