Implicit conversion causes stack overflow
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
}
精彩评论