Given this code:
trait S {
def s: String
}
trait I {
def i: Int
}
case class CC_S(s: String) extends S
case class CC_I(i: Int) extends I
case class CC_S_I(s: String, i: Int) extends S with I
def combine(s: S, i: I): S with I = CC_S_I(s.s, i.i)
This test succeeds:
Assert.assertEquals(CC_S_I("s", 1), combine(CC_S("s"), CC_I(1)))
(How) can I make the combine method generic as a trait with type parameters? I.e. I would like to define something like this:
trait MyTrait[A,B] {
def combine(a: A, b: B): A with B
}
So that I can use it like this:
class MyClass[A <: CC_S, B <: CC_I] extends MyTrait[A,B] {
override def combine(s: A, i: B) = CC_S_I(s.s, i.i) //Note: this line does not compile...
}
Assert.assertEquals(CC_S_I("s", 1), new MyClass().combine(CC_S("s"), CC_I(1)))
Update. This would have been a better example:
class MyClass[A <: S, B <: I] extends MyTrait[A,B] {
override def combine(s: A, i: B) = CC_S_I(s.s, i.i) //Note: this line does not compile...
}
See comments under Travis’s answer to see that answered as well.
The problem is just that
CC_S_Iisn’t actually a subtype of eitherCC_SorCC_I(although it is a subtype ofSandI). The following will work:As a side note, the Shapeless library is worth looking into if you’re doing much of this kind of thing. It allows you to write your
combinemethod very generically:Now you just need a bit of boilerplate:
And you can write:
The enormous type annotation is unfortunately necessary with this formulation, but this should give you some idea of what’s possible, and there are things you could do to make the usage cleaner.