Manuel Schmidt
Manuel Schmidt

Reputation: 2489

Using Guavas Range in Scala

I would like to use Guavas Range from Scala. However it expects the elements to implement the Comparable interface. So I cannot simply use

val range = Range.open(4, 5)

since Int does not implement Comparable or Ordered. However there is an Ordering[Int] type class. The only idea I have so far is to use view bounds

def open[T](from:T, to:T)(implicit ord: T => Ordered[T]) = Range.open(ord(from), ord(to))

but I get a CCE:

 val range = open(4,5)                           //> java.lang.ClassCastException: scala.runtime.RichInt cannot be cast to java.l
                                                  //| ang.Integer
                                                  //|   at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:106)
                                                  //|   at scala.math.Ordering$Int$.compare(Ordering.scala:256)
                                                  //|   at scala.runtime.OrderedProxy$class.compare(ScalaNumberProxy.scala:71)
                                                  //|   at scala.runtime.RichInt.compare(RichInt.scala:15)
                                                  //|   at scala.math.Ordered$class.compareTo(Ordered.scala:91)
                                                  //|   at scala.runtime.RichInt.compareTo(RichInt.scala:15)
                                                  //|   at com.google.common.collect.Range.compareOrThrow(Range.java:711)
                                                  //|   at com.google.common.collect.Cut.compareTo(Cut.java:75)
                                                  //|   at com.google.common.collect.Range.<init>(Range.java:364)
                                                  //|   at com.google.common.collect.Range.create(Range.java:156)
                                                  //|   at com.google.common.collect.Range.open(Range.java:168)

Why does this result in a ClassCastException?

Is there a better way to do this? Note: using Int is just a minimal example. I have more complex types that don't implement Ordered but with an Ordering in scope.

Upvotes: 2

Views: 867

Answers (2)

Markus
Markus

Reputation: 242

You get an CCE because RichInt does not implement Ordered[RichInt] but Ordered[Int].

I suggest you wrap it by yourself similar to

case class AsOrdered[T](val value: T)(implicit ord: Ordering[T]) extends Ordered[AsOrdered[T]] {
  override def compare(that: AsOrdered[T]) = ord.compare(value, that.value)
}

def open[T: Ordering](from: T, to: T) = {
  val ord = implicitly[Ordering[T]]
  Range.open(AsOrdered(from), AsOrdered(to))
} 

You need to provide additional logic to extract the values since you will not get a Range[Int] but a Range[AsOrdered[Int]]

Edit:

We just released a version of Mango that contains a Range/RangeSet wrapping the Guava implementations taking an Ordering.

Upvotes: 2

Rex Kerr
Rex Kerr

Reputation: 167891

Just explicitly specify that you want to box to a java.lang.Integer:

import java.lang.{Integer => jI}
Range.open[jI](3,5)

If you don't like doing this on every call, wrap the calls as you suggested.

Upvotes: 4

Related Questions