开发者

Why do I get "Could not find implicit value for parameter ord: scala.math.Ordering[T]"

I have a simple example trait, which has a value of some generic type descended from Ordered. I can't find any way to actually use the value though as I get "Could not find implicit value for parameter ord: scala.math.Ordering[T]". Here's the code:

trait Example[T <: Ordered[_]] {
  val key: T

  def before(that: Example[T]): Boolean = (key < that.ke开发者_开发百科y)    
}

Any ideas why this doesn't compile?


looks to me like it should be

trait Example[T <: Ordered[T]] {


I believe, I does not compile, because you saying that T should be Ordered on any type. We can write an equivalent trait like this (please, correct me, if I'm wrong - I'm not sure whether it can be considered equivalent, but at least you will receive the same error from compiler):

trait Example1[A, T <: Ordered[A]] {
    val key: T

    def before(that: Example1[A, T]): Boolean = (key < that.key)
}

If you look in the Ordered trait definition you will find something like this:

trait Ordered[A] extends java.lang.Comparable[A] {
  ...

  def <  (that: A): Boolean = (this compare that) <  0
  ...
}

object Ordered {  
  /** Lens from Ordering[T] to Ordered[T] */
  implicit def orderingToOrdered[T](x: T)(implicit ord: Ordering[T]): Ordered[T] = 
    new Ordered[T] { def compare(that: T): Int = ord.compare(x, that) }
}

When we will think in terms of this definition - if key is Ordered[A] than that.key should be of type A (according to < method signature). So compiler can't actually use it on Ordered[A] or in other words T. And if I'm not mistaking it tries to find some Ordering[T] (according to implicit definition in companion object) that can be used as last resort (but it fails).

So if you will define type parameter T like T <: Ordered[T] it will compile.

As another solution to this problem you can use context bound like in this example:

abstract class Example[T: Ordering] {
  val key: T
  val ord = implicitly[Ordering[T]]
  import Ordered._

  def before(that: Example[T]): Boolean = key < that.key
}

var one = new Example[Int] {val key = 1}
var two = new Example[Int] {val key = 2}

println(one.before(two)) // prints: true
println(two.before(one)) // prints: false

In this case implicit conversion would actually be used because we have evidence, that Ordering[T] exists (traits can't have context or view bound, so I created abstract class)

Does it makes sense? If you find flaws in my logic - please comment! (I will appreciate this)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜