Given:
case class Person(name: String)
and trying to do:
scala> List(Person("Tom"), Person("Bob")).sorted
results in a complaint about missing Ordering.
<console>:8: error: could not find implicit value for parameter ord: Ordering[Person]
List(Person("Tom"), Person("Bob")).sorted
However this:
case class Person(name: String) extends Ordered[Person] {
def compare(that: Person) = this.name compare that.name }
works fine as expected:
scala> List(Person("Tom"), Person("Bob")).sorted
res12: List[Person] = List(Person(Bob), Person(Tom))
although there's no Ordering or implicits involved.
Question #1: what's going on here? (My money is on something implicit...)
However, given the above and the fact that this:
scala> Person("Tom") > Person("Bob")
res15: Boolean = true
works, and that also this:
scala> List(Some(2), None, Some(1)).sorted
works out of the box:
res13: List[Option[Int]] = List(None, Some(1), Some(2))
I would expect that this:
scala> Some(2) > Some(1)
would also work, however it does not:
<console>:6: error: value > is not a member of Some[Int]
Some(2) > Some(1)
Question #2: why not, and how can I get it to work?
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With