开发者

Implicit conversion causes stack overflow

开发者 https://www.devze.com 2023-02-04 19:15 出处:网络
The following code snippet worked perfectly, then after some code changes in different files, I\'ve started getting stack overflows resulting from recursive invocation of the implicit conversion. Has

The following code snippet worked perfectly, then after some code changes in different files, I've started getting stack overflows resulting from recursive invocation of the implicit conversion. Has this ever happened to anyone, and if so what's the fix.

implicit def comparable2ordered[A <:开发者_Python百科 Comparable[_]](x: A): Ordered[A] =
new Ordered[A] with Proxy {
  val self = x

  def compare(y: A): Int = {
    self.compareTo(y)
  }
} 


Firstly, I think that the reason for your stack overflow is the usage of [A <: Comparable[_]]. The existential type means in practice that you cannot actually compare an A to anything. This means that the compiler is "selecting" the implicit conversion to re-invoke in the self.compareTo call (hence the recursion). You would see this if you used the compiler switch -XprintTypes

So what to do?


Consider the difference between an Ordering and an Ordered. There should be an implicit ordering for your type.

implicit def comp2ord[A <: Comparable[A]] = new Ordering[A] {
  def compare(x : A, y : A) = x compareTo y
}

And then a way of turning this ordering into an Ordered:

implicit def ordering2order[A : Ordering](x : A) = new Ordered[A] {
  def compare(y : A) = implicitly[Ordering[A]].compare(x, y)
}

Usage with no implicit ordering:

scala> val df = new java.text.SimpleDateFormat("yyyy-MM-dd")
df: java.text.SimpleDateFormat = java.text.SimpleDateFormat@f67a0200

scala> TreeSet(df.parse("2011-03-04"), df.parse("2010-05-06"))
<console>:13: error: could not find implicit value for parameter ord: Ordering[java.util.Date]
   TreeSet(df.parse("2011-03-04"), df.parse("2010-05-06"))
          ^

Now with an implicit ordering...

scala> implicit def comp2ord[A <: Comparable[A]] = new Ordering[A] {
 | def compare(x : A, y : A) = x compareTo y
 | }
comp2ord: [A <: java.lang.Comparable[A]]java.lang.Object with Ordering[A]

scala> TreeSet(df.parse("2011-03-04"), df.parse("2010-05-06"))
res1: scala.collection.immutable.TreeSet[java.util.Date] = TreeSet(Fri Mar 04 00:00:00 GMT 2011, Thu May 06 00:00:00 BST 2010)

Of course, you would also need an implicit conversion from an Ordering to an Ordered in order to take advantage of scala's comparisons via <, >= etc:

scala> implicit def ordering2order[A : Ordering](x : A) = new Ordered[A] {
 | def compare(y : A) = implicitly[Ordering[A]].compare(x, y)
 | }
ordering2order: [A](a: A)(implicit evidence$1: Ordering[A])java.lang.Object with Ordered[A]

scala> df.parse("2010-04-05") < df.parse("2009-01-01")
res2: Boolean = false

In the case that your type A is a Java class which implements the raw-type Comparable, you will have to provide an explicit conversion:

implicit def comp2ord(x : DateTime) = new Ordered[DateTime] {
  def compare(y : DateTime) = x compareTo y
}
0

精彩评论

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

关注公众号