Reputation: 8495
I want to make the following trait covariant, knowing that DistTraversableLike
is covariant in both its type parameters:
trait TraversableNumOps[T, Repr] extends DistTraversableLike[T, Repr] {
private def min(a: T, b: T)(implicit num: Numeric[T]) =
if (num.compare(a, b) <= 0) a else b
private def max(a: T, b: T)(implicit num: Numeric[T]) =
if (num.compare(a, b) > 0) a else b
def maxD(implicit num: Numeric[T]): Option[T] =
reduceD((a, b) => if (a >= b) a else b)
def minD(implicit num: Numeric[T]): Option[T] =
reduceD((a, b) => if (a < b) a else b)
def sumD(implicit num: Numeric[T]): Option[T] =
reduceD(_ + _)
def productD(implicit num: Numeric[T]): Option[T] =
reduceD(_ * _)
}
However, I haven't been able to manage this without breaking it. The problem is that I want to support Numeric[T]
which is not covariant in T.
How can I modify this trait to become covariant in T
and Repr
?
Upvotes: 2
Views: 378
Reputation: 32335
Repr
should not be a problem, since it does not appear as the type for any of the method arguments.
However, T
does occur in contravariant position.
You can amend this by putting a private[this]
modifier on min
and max
. This will ensure that these methods are only used from within the current object, and variance violations can be checked by the compiler within the scope of the current object.
For maxD
and others, consider making them take a supertype of T
:
def maxD[U >: T](implicit num: Numeric[U]): Option[U]
This solves the variance issues, because there is no way to use a supertype U
of T
and violate variance (e.g. you cannot assign it to a field of the object, because the TraversableNumOps
cannot have a field of type U
).
Upvotes: 2