Reputation: 715
EDITED AFTER TWO ANSWERS BELOW I am trying to make the following Scala code to compile.
abstract class C {
type T <: C
def x(other: T): (T, T)
}
class C1 extends C {
override type T = C1
override def x(other: C1): (C1, C1) = (this, this)
}
def doSthg(cs1 : List[C]) {
val e1 = cs1(0)
val e2 = cs1(1)
e1.x(e2)
}
But fails with the following message:
Description Resource Path Location Type
type mismatch; found : e2.type (with underlying type Chromo[G]) required: e1.C PI3.sc /GA/src/org/jts/ga line 76 Scala Problem
type mismatch; found : e2.type (with underlying type org.jts.ga.MI2.C) required: e1.T MI2.sc /GA/src/org/jts/ga line 18 Scala Problem
Any idea?
Basically, I want to define a generic class like C above, and have methods with the right type on a subclass (C1).
All is good until a generic method is called on C in soSthg.
Thanks
NEW EDIT SECTION
Thanks v much for your replies. Looking at the following code, I was hoping to avoid asInstanceOf.
abstract class G[T](val t: T) {
def ~(): G[T]
}
abstract class C[T](val g: List[G[T]]) {
def x(other: C[T]): (C[T], C[T])
}
class G1(override val t: Boolean) extends G[Boolean](t){
override def ~() = new G1(!t)
}
class C1(override val g: List[G1]) extends C[Boolean](g) {
override def x(other: C[Boolean]): (C[Boolean], C[Boolean]) = {
val go = other.g.map(e => e.asInstanceOf[G1])
//val go = other.g
val nc1 = new C1(go)
(nc1, nc1) // for demo
}
}
The signature of x(other: C[Boolean]) is the issue indeed.
This would work:
def doSthg2[T <: C](csl : List[T]) { csl(0).x(csl(1)) }
How to avoid asInstanceOf ?
Upvotes: 1
Views: 211
Reputation: 23105
There's no problem defining C & C1 as above. The problem is that you're passing an argument to e1.x that is of type C (not C1) and so violates your C1.x method signature.
As far as the compiler is concerned:
C
doSthg
, the vals e1
& e2
are each of some type within the hierarchy. For e1 & e2, the only things known for sure are that e1.type
and e2.type
are each subtypes of C
. There's no guarantee that e1
and e2
are of the same type (or are subtypes of one another) - even though the class hierarchy is very shallow (just one subclass, C1
). You could extend by adding new subtypes of C
in new .class/.jar files at any point in the future (possibly generated from .scala/.java files from this compiler on this machine, or even by a different compiler on a different machine!)C1.x
is not flexible - it's argument must be of type C1
, not any C
. Hence, e1.x
cannot take an 'arbitrary' e2 <: C
as argument.So the compiler is doing the right thing, based on your design decisions. Solutions:
C1.x
to take arguments of type C
List[C1]
(possibly moving doSthg within C1 at the same time)Upvotes: 1
Reputation: 38045
C1
compiles fine. Note that you could remove override
keyword here:
class C1 extends C {
type T = C1
def x(other: C1): (C1, C1) = (this, this) // do you mean (other, this)?
}
doSthg
is just invalid: you can't prove that e2
is e1.T
. This works as expected:
def doSthg(e1: C)(e2: e1.T) {
e1.x(e2)
}
Or this:
abstract class C {
...
def create(): T
}
def doSthg(e1: C) {
val e2 = e1.create()
e1.x(e2)
}
For your original doSthg
method x
should accept any instance of C
:
trait C {
def x(other: C): (C, C)
}
Upvotes: 10