Generics in a bidirectional association
- by Verhoevenv
Let's say I have two classes A and B, with B a subtype of A. This is only part of a richer type hierarchy, obviously, but I don't think that's relevant. Assume A is the root of the hierarchy. There is a collection class C that keeps track of a list of A's. However, I want to make C generic, so that it is possible to make an instance that only keeps B's and won't accept A's.
class A(val c: C[A]) {
c.addEntry(this)
}
class B(c: C[A]) extends A(c)
class C[T <: A]{
val entries = new ArrayBuffer[T]()
def addEntry(e: T) { entries += e }
}
object Generic {
def main(args : Array[String]) {
val c = new C[B]()
new B(c)
}
}
The code above obviously give the error 'type mismatch: found C[B], required C[A]' on the new B(c) line.
I'm not sure how this can be fixed. It's not possible to make C covariant in T (like C[+T <: A]) because the ArrayBuffer is non-variantly typed in T. It's not possible to make the constructor of B require a C[B] because C can't be covariant.
Am I barking up the wrong tree here? I'm a complete Scala newbie, so any ideas and tips might be helpful. Thank you!
EDIT:
Basically, what I'd like to have is that the compiler accepts both
val c = new C[B]()
new B(c)
and
val c = new C[A]()
new B(c)
but would reject
val c = new C[B]()
new A(c)
It's probably possible to relax the typing of the ArrayBuffer in C to be A instead of T, and thus in the addEntry method as well, if that helps.