Say I have two classes with the same identifier for a parameterized type
trait A {
type O
def f(a: Int, os: Seq[O]): Int
}
trait B {
type O
def g(a: Int, o: O): Int = { h1(o) + h2(a) }
def h1(o: O): Int
def h2(a: Int): Int = {a/2}
}
I would like to create a child class that will “marry” the two
trait C extends A with B {
def f(a: Int, os: Seq[O]): Int = {
os.map{ o => g(a, o) }.sum
}
}
Finally, I create an implementation for C
class D extends C {
type O = Int
def h1(o: O): Int = {5 * o}
}
At writing of C I don’t yet know what type O is — however, I’d like to constrain A.O == B.O such that it “makes sense” to use B.g in an implementation of A.f. I tried implementing this and it surprisingly seemed like Scala assumed there was only ever one type O
val d = new D
println(d.f(1, Seq(1,2,3)))
To me this seems incorrect — why should A.O and B.O agree?
EDIT
I’d also like to note that If you were to instead put constraints on O like so,
case class Z()
case class Z1() extends Z
case class Z2() extends Z1
trait A {
type O <: Z
}
trait B {
type O >: Z2
}
class D extends C {
type O = Z1
Compilation will fail. However, if you put this instead,
trait A {
type O <: Z
}
trait B {
type O <: Z1
}
class D extends C {
type O = Z2
Compilation succeeds and everything runs fine.
I think Scala always “marries” the members — both type and value members — of traits when both are mixed in:
gives
(it’s how Scala deals with the multiple inheritance issue — no matter how many times an identifier is mixed in, it only exists once).