I have a case class, like this:
case class Container[T, M](value: T, modifier: M)
I want to make it possible to have an Ordering
on Container
for those T
that have an Ordering
too. I don't want to make T <: Ordered[T]
, because Container
should be able to contain non-orderable values as well.
My first try was to implement Ordered
, like this:
case class Container[T, M](value: T, modifier: M) extends Ordered[Container[T, M]] {
override def compare(that: Container[T, M])(implicit ev: Ordering[T]): Int = ev.compare(value, that.value)
}
But that obviously doesn't work: because of the implicit
parameter, compare
no longer implements the trait.
So then I decided to try a type class approach:
class ContainerOrdering[T, M](implicit ev: Ordering[T]) extends Ordering[Container[T, M]] {
override def compare(x: Container[T, M], y: Container[T, M]): Int = ev.compare(x.value, y.value)
}
implicit object ContainerOrderingInt extends ContainerOrdering[Int, Int]
This works (if I also import Ordering.Implicits._
), but now I have a new problem: for every type M
, I need a separate implicit object. Now there aren't too many types that I want to use in the M
position (in fact, they all derive from a sealed trait that I define elsewhere), but still it means a combinatorial explosion of implicit objects that I need to define. I'm OK with having a separate implicit object for each T
, but M
really should be orthogonal to this.
There must be a better way to do this. Maybe I can leverage the fact that M
extends a sealed trait. However, I haven't been able to do so. Any advice?