Ordering and Ordered and comparing Options

If you install the slightly-too-magical-for-default-scope bonus implicits, you can compare options like so:

scala> import scala.math.Ordering.Implicits._
import scala.math.Ordering.Implicits._

scala> def cmpSome[T: Ordering](x: Option[T], y: Option[T]) = x < y
cmpSome: [T](x: Option[T], y: Option[T])(implicit evidence$1: Ordering[T])Boolean

The import gives you an implicit from an Ordering to the class with the infix operations, so that it's enough to have the Ordering without another import.


To answer your second question, why can't you do this: Some(2) > Some(1)

You can, with an import and working with Option[Int] rather than Some[Int].

@ import scala.math.Ordering.Implicits._ 
import scala.math.Ordering.Implicits._
@ Some(2) > Some(1) // doesn't work
cmd11.sc:1: value > is not a member of Some[Int]
val res11 = Some(2) > Some(1)
                    ^
Compilation Failed
@ (Some(2): Option[Int]) > (Some(1): Option[Int]) // Option[Int] works fine
res11: Boolean = true
@ Option(2) > Option(1) 
res12: Boolean = true
@ (None: Option[Int]) > (Some(1): Option[Int]) 
res13: Boolean = false

In practice your types will probably be of Option[Int] rather than Some[Int] so it won't be so ugly and you won't need the explicit upcasting.


The definition of List's sorted method is:

def sorted [B >: A] (implicit ord: Ordering[B]): List[A]

So yes, implicit things are happening, but many classes in the standard library have implicit objects associated with them without you having to import them first.

The Ordering companion object defines a bunch of implicit orderings. Among these is an OptionOrdering and IntOrdering, which helps explain the ability of a list to call sorted.

To gain the ability to use operators when there is an implicit conversion available, you need to import that object, for example:

def cmpSome(l:Option[Int], r:Option[Int])(implicit ord:Ordering[Option[Int]]) = {
  import ord._
  l < r
}

scala> cmpSome(Some(0), Some(1))
res2: Boolean = true

Concerning your first question: Ordered[T] extends Comparable[T]. The Ordering companion object provides an implicit Ordering[T] for any value that can be converted into a Comparable[T]:

implicit def ordered[A <% Comparable[A]]: Ordering[A]

There is no implicit conversion A : Ordering => Ordered[A] - that's why Some(1) > Some(2) will not work.

It is questionable if it is a good idea to define such a conversion as you may end up wrapping your objects into Ordered instances and then create an Ordering of that again (and so on...). Even worse: you could create two Ordered instances with different Ordering instances in scope which is of course not what you want.

Tags:

Scala