Reputation: 12839
I have two structurally-equivalent class pairs whose only difference is the types. I would like to be able to merge V1
with V2
and K1
with K2
. I control those four classes, but I am not able to modify takesDoublesOrLists
- it comes from a library.
class V1 (
val a: Double,
val b: Double,
// ...
val z: Double
)
class K1(v: V1) {
def doIt = takesDoublesOrLists(v.a, v.b, /* ..., */ v.z)
}
class V2 (
val a: List[Double],
val b: List[Double],
// ...
val z: List[Double]
)
class K2(v: V2) {
def doIt = takesDoublesOrLists(v.a, v.b, /* ..., */ v.z)
}
I tried following the type class pattern, but got an error that the overloaded method takesDoublesOrLists
could not be applied to my type parameter.
Edit:
The signature of the overloaded function takesDoublesOrLists
is as the name suggests:
def takesDoublesOrLists(a: Double, b: Double, /* ..., */ z: Double): Something = /* ... */
def takesDoublesOrLists(a: List[Double], b: List[Double], /* ..., */ z: List[Double]): Something = /* ... */
Upvotes: 3
Views: 107
Reputation: 170835
I tried following the type class pattern, but got an error that the overloaded method takesDoublesOrLists could not be applied to my type parameter.
You don't show your attempt, but you shouldn't be calling the overloaded version of takesDoublesOrLists
, it should be part of the typeclass (of course, you can call the existing version when implementing it, if there are reasons not to move the implementation there):
sealed trait DoubleOrList[A] {
def doIt(a: A, b: A, /* ..., */ z: A): Something
}
object DoubleOrList {
implicit object DoubleIsDoubleOrList extends DoubleOrList[Double] {
def doIt(a: Double, b: Double, /* ..., */ z: Double): Something =
SomeObject.takesDoublesOrLists(a, b, z)
}
implicit object ListIsDoubleOrList extends DoubleOrList[List[Double]] {
def doIt(a: List[Double], b: List[Double], /* ..., */ z: List[Double]): Something =
SomeObject.takesDoublesOrLists(a, b, z)
}
}
// this context bound isn't really necessary, but it prevents you from creating V[String] you can't use
class V[A: DoubleOrList](
val a: A,
val b: A,
// ...
val z: A
)
class K[A](v: V[A])(implicit dOrL: DoubleOrList[A]) {
def doIt = dOrL.doIt(v.a, v.b, /* ..., */ v.z)
}
Upvotes: 1
Reputation: 10998
I can see how you could merge V1
and V2
, but not K1
or K2
:
class V[T] (
val a: T,
val b: T
// ...
val z: T
)
class K1(v: V[Double]) {
def doIt = takesDoublesOrLists(v.a, v.b, /* ..., */ v.z)
}
class K2(v: V[List[Double]]) {
def doIt = takesDoublesOrLists(v.a, v.b, /* ..., */ v.z)
}
EDIT: If your K1 and K2 classes are more complex than what you exemplified, you could break this behavior with traits:
trait KDoubles {
def v: V[Double]
def doIt = takesDoublesOrLists(v.a, v.b, /* ..., */ v.z)
}
trait KLists {
def v: V[List[Double]]
def doIt = takesDoublesOrLists(v.a, v.b, /* ..., */ v.z)
}
class K {
// common stuff ...
}
class K1 extends K with KDoubles {
// ...
}
class K2 extends K with KLists {
// ...
}
Upvotes: 1