Generics in a bidirectional association

Posted by Verhoevenv on Stack Overflow See other posts from Stack Overflow or by Verhoevenv
Published on 2011-01-08T04:39:57Z Indexed on 2011/01/08 18:53 UTC
Read the original article Hit count: 177

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.

© Stack Overflow or respective owner

Related posts about generics

Related posts about inheritance