MaatDeamon
MaatDeamon

Reputation: 9761

How Implicit Ordering[Option[T]] works in scala?

I'm playing a bit with implicit resolution, and wanted to understand what this implicit val useful for ? In Ordering we have

trait OptionOrdering[T] extends Ordering[Option[T]] {
    def optionOrdering: Ordering[T]
    def compare(x: Option[T], y: Option[T]) = (x, y) match {
      case (None, None)       => 0
      case (None, _)          => -1
      case (_, None)          => 1
      case (Some(x), Some(y)) => optionOrdering.compare(x, y)
    }
  }
  implicit def Option[T](implicit ord: Ordering[T]): Ordering[Option[T]] =
    new OptionOrdering[T] { val optionOrdering = ord }

I wonder when is implicit def Option[T](implicit ord: Ordering[T]): Ordering[Option[T]] useful or called.

I tried the following:

def test[Option[T]: Ordering](value1: Option[T], value2: Option[T]) = {
  val e = implicitly(Ordering[Option[T]]).compare(value1, value2)
}

But the compiler does not like it.

not found: type T def test[Option[T]: Ordering](value1: Option[T], value2: Option[T]) = {

and if i do which granted might not make sense but just for the sake

def test[Option[Int]: Ordering](value1: Option[Int], value2: Option[Int]) = {
  val e = implicitly(Ordering[Option[Int]]).compare(value1, value2)
}

I get 

type Option takes type parameters
def test[Option[Int]: Ordering](value1: Option[Int], value2: Option[Int]) = {
No implicit Ordering defined for Option[Int]

Can someone give an example of how to use that implicit and or where is it useful and actually used ?

My assumption is that when there is a need of an Ordering[Option[T]] then this function is called to resolve the implicit. But i am not able to make that happen ....

EDIT Well i wrote the following which make more sense

def test(value1: Option[Int], value2: Option[Int]) = {
  val e = implicitly(Ordering[Option[Int]]).compare(value1, value2)
}

Then what i don't understand is the context Bound issue with

def test[Option[T]: Ordering](value1: Option[T], value2: Option[T]) = {
  val e = implicitly(Ordering[Option[T]]).compare(value1, value2)
}

What's wrong with writing a context bound like that ?

Upvotes: 1

Views: 616

Answers (1)

Mario Galic
Mario Galic

Reputation: 48420

I wonder when is implicit def Option[T](implicit ord: Ordering[T]): Ordering[Option[T]] useful or called.

Implicit methods can be used to construct type class instances out of other type class instances which can save boilerplate

implicit def Option[T](implicit ord: Ordering[T]): Ordering[Option[T]] =
  new OptionOrdering[T] { val optionOrdering = ord }

For example given type class instance Ordering[Int] the above implicit method can construct type class instance Ordering[Option[Int]]. (Do not forget the implicit parameter, otherwise we get implicit conversion which is frowned upon).

what's wrong with [Option[T]: Ordering]

The key is to understand the difference between type constructor and proper type. For example Option is a type constructor that can construct proper type Option[Int]. The type parameter clause [Option[T]: Ordering] in your definition

def test[Option[T]: Ordering](value1: Option[T], value2: Option[T])

does not actually specify Option type constructor. It just happens that you named it the same however what you have specified is actually more like

def test[F[T]: Ordering](value1: F[T], value2: F[T])

Furthermore, T in F[T] cannot actually be used in the method parameter list, so in fact your definition is more like so

def test[F[_]: Ordering](value1: F[T], value2: F[T])

Now the errors should be clearer; F[_]: Ordering is requiring type class instance Ordering[F] where F is a type constructor however there are no such type class instances because the definition of type class Ordering is

trait Ordering[T]

where T is a proper type. Otherwise it would be defined something like

trait Ordering[F[_]]

An example of such a type class is Functor

trait Functor[F[_]]

Hence to syntactically fix your definition try something like

def test[T](value1: Option[T], value2: Option[T])(implicit ev: Ordering[Option[T]]) = {
  ev.compare(value1, value2)
}

test(Some(1), Some(42))
// res0: Int = -1

implicitly[Ordering[Option[Int]]].compare(Some(1), Some(42))
// res1: Int = -1

Here test(Some(1), Some(42)) is equivalent to

test[Int](Some(1), Some(42))(Option[Int])
                                |
                         implicit method call

Upvotes: 4

Related Questions