"diverging implicit expansion" error, another instance of 8541, or something else?

Is this another instance of 8541, or something else?

$ scala
Welcome to Scala 2.12.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_162).
Type in expressions for evaluation. Or try :help.

scala> abstract class Z extends Ordered[Z] { val i: Int; def compare(that: Z): Int = i.compareTo(that.i); }
defined class Z

scala> case class A(i: Int, s: String) extends Z
defined class A

scala> scala.collection.mutable.TreeSet(A(1, "one"), A(2, "two"))
<console>:14: error: diverging implicit expansion for type Ordering[A]
starting with method $conforms in object Predef
       scala.collection.mutable.TreeSet(A(1, "one"), A(2, "two"))
                                       ^

What’s the best way of avoiding the problem? Thanks.

more detail:

scala> :settings -Xlog-implicits

scala> scala.collection.mutable.TreeSet(A(1, "one"), A(2, "two"))
<console>:14: math.this.Ordering.comparatorToOrdering is not a valid implicit value for Ordering[A] because:
hasMatchingSymbol reported error: could not find implicit value for parameter cmp: java.util.Comparator[A]
       scala.collection.mutable.TreeSet(A(1, "one"), A(2, "two"))
                                       ^
<console>:14: $conforms is not a valid implicit value for A => Comparable[A] because:
hasMatchingSymbol reported error: type mismatch;
 found   : A <:< A
 required: A => Comparable[A]
       scala.collection.mutable.TreeSet(A(1, "one"), A(2, "two"))
                                       ^
<console>:14: math.this.Ordering.comparatorToOrdering is not a valid implicit value for scala.math.Ordering[A] because:
hasMatchingSymbol reported error: could not find implicit value for parameter cmp: java.util.Comparator[A]
       scala.collection.mutable.TreeSet(A(1, "one"), A(2, "two"))
                                       ^
<console>:14: math.this.Ordering.ordered is not a valid implicit value for scala.math.Ordering[A] because:
hasMatchingSymbol reported error: diverging implicit expansion for type A => Comparable[A]
starting with method orderingToOrdered in object Ordered
       scala.collection.mutable.TreeSet(A(1, "one"), A(2, "two"))
                                       ^
<console>:14: math.this.Ordering.comparatorToOrdering is not a valid implicit value for scala.math.Ordering[A] because:
hasMatchingSymbol reported error: could not find implicit value for parameter cmp: java.util.Comparator[A]
       scala.collection.mutable.TreeSet(A(1, "one"), A(2, "two"))
                                       ^
<console>:14: math.this.Ordering.ordered is not a valid implicit value for scala.math.Ordering[A] because:
hasMatchingSymbol reported error: diverging implicit expansion for type A => Comparable[A]
starting with method orderingToOrdered in object Ordered
       scala.collection.mutable.TreeSet(A(1, "one"), A(2, "two"))
                                       ^
<console>:14: math.this.Ordered.orderingToOrdered is not a valid implicit value for A => Comparable[A] because:
hasMatchingSymbol reported error: diverging implicit expansion for type A => Comparable[A]
starting with method $conforms in object Predef
       scala.collection.mutable.TreeSet(A(1, "one"), A(2, "two"))
                                       ^
<console>:14: math.this.Ordering.ordered is not a valid implicit value for Ordering[A] because:
hasMatchingSymbol reported error: diverging implicit expansion for type A => Comparable[A]
starting with method orderingToOrdered in object Ordered
       scala.collection.mutable.TreeSet(A(1, "one"), A(2, "two"))
                                       ^
<console>:14: error: diverging implicit expansion for type Ordering[A]
starting with method $conforms in object Predef
       scala.collection.mutable.TreeSet(A(1, "one"), A(2, "two"))
                                       ^

I’m pretty sure it is.

When you are in control of the code the best way would probably be not extending Ordered, but providing an instance of Ordering yourself.

I guess what you want is something like

implicit def OrderingZ[T <: Z]: Ordering[T] = ???

Thanks for that @Jasper-M. Based on a post on SO, I ended up with this alternative, which makes my head spin but also seems to work:

scala> abstract class Z[T <: Z[T]] extends Ordered[T] { val i: Int; def compare(that: T): Int = i.compareTo(that.i); }
defined class Z

scala> case class A(i: Int, s: String) extends Z[A]
defined class A

scala> scala.collection.mutable.TreeSet(A(1, "one"), A(2, "two"), A(3, "three"))
res0: scala.collection.mutable.TreeSet[A] = TreeSet(A(1,one), A(2,two), A(3,three))

I get a similar diverging implicit expansion for type scala.math.Ordering[A] and have read the bug report which looks like its built in for now. The problem comes with something along the following lines:

MyClassA(val num: Int) extends Ordered[MyClassA] and defines a compare method that does this.num - that.num

type MyPair = (MyClassA, MyClassA)

private var mySet : Set[MyPair] = TreeSet()

I think Jasper’s implicit def OrderingZ[T <: Z]: Ordering[T] = ??? might be the best solution but I’m struggling to see how do this for MyPair which are just tuples and the constituents already have a compare method.

It’s probably an easy one for those aleady conversant in Orderings.

Your example with MyClassA and MyPair just works though.

Hmm. Yes, it did with me too, yet the above example is the essence of the problem within my larger program which does error, given my mySet set object is just a set of pairs of a particular class to which I have added a compare method.

I’ve run a test this morning - this is Test.scala

import collection.immutable._

class A(val id : Int) extends Ordered[A]{
  def compare(that: A) = this.id - that.id
}


class B () {
  type Tu = (A,A)
  private var mySet: Set[Tu] = TreeSet()
}

which compiles fine, yet if I include other scala files in the compilation it errors with

Test.scala:15: error: diverging implicit expansion for type scala.math.Ordering[A] starting with method ordered in trait LowPriorityOrderingImplicits private var mySet: Set[Tu] = TreeSet()

If I change the definition to private var mySet: Set[Tu] = TreeSet[Tu]() I get

Test.scala:15: error: diverging implicit expansion for type scala.math.Ordering[(A, A)] starting with method $conforms in object Predef private var mySet: Set[Tu] = TreeSet[Tu]()

Given it works in isolation, I’m not sure where to go from here.