My code:
import Ordered.orderingToOrdered
import java.util.Date
val (d1, d2) = (Option(new Date()), Option(new Date()))
d1 compare d2
result with -Xlog-implicits:
Information:(268, 5) math.this.Ordering.Option is not a valid implicit value for
scala.math.Ordering[Option[java.util.Date]] because:
diverging implicit expansion for type scala.math.Ordering[Option[java.util.Date]]
starting with method ordered in trait LowPriorityOrderingImplicits
d1 compare d2
^
Information:(268, 5) math.this.Ordering.comparatorToOrdering is not a valid implicit
value for scala.math.Ordering[Option[java.util.Date]] because:
diverging implicit expansion for type scala.math.Ordering[Option[java.util.Date]]
starting with method ordered in trait LowPriorityOrderingImplicits
d1 compare d2
^
Error:(268, 5) diverging implicit expansion for type
scala.math.Ordering[Option[java.util.Date]]
starting with method ordered in trait LowPriorityOrderingImplicits
d1 compare d2
^
I think what happens here is a cycle between Ordered and Ordering - implicit Ordering[Option[Date]] is in scope because it's defined in object Ordering and it it is a subclass of java.util.Comparator, so you can use it to create another ordering...
This is compiled against scala 2.10, it seems that there were changes in this area in 2.11, but scalac entered infinite loop when I tried to upgrade scala.
Edit:
Just to show I'm not clueless, I fixed it for the time being with substituting import Ordered._
with my import OrderedFix._
:
/** Avoid implicit cycles between scala Ordered and Ordering */
trait OrderedFix[T] {
def compare(that :T) :Int
def < (that :T) = compare(that) <0
def <=(that :T) = compare(that) <=0
def > (that :T) = compare(that) >0
def >=(that :T) = compare(that) >=0
}
object OrderedFix {
implicit def ordered[T :Ordering](self :T) :OrderedFix[T] = new OrderedFix[T] {
def compare(that :T) = implicitly[Ordering[T]].compare(self, that)
}
}
But this is silly, that's what the stdlib should provide...
The use of the Ordered
trait is considered bad style by many people. The preferred way is to stick to the Ordering
type class. The following is an example of using just Ordering
:
val (d1, d2) = (Option(new Date()), Option(new Date()))
val ord = Ordering[Option[Date]]
import ord._
compare(d1, d2)
d1 < d2
d1 equiv d2
Here the import
both gets you function compare
into scope as well as extension methods that allow the infix operators shown in the last two lines.