Reputation: 9761
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
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