Felix
Felix

Reputation: 8495

How to make this trait covariant

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

Answers (1)

axel22
axel22

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

Related Questions