Reputation: 1454
In Scala. I have two objects of type Any. If it's possible, I'd like to cast the objects to the correct Ordered trait, and then compare them with the < method. Otherwise, I want to throw an exception. Should be simple, but I'm stumped...
Upvotes: 3
Views: 1282
Reputation: 26586
You can implement this with Ordering
type class:
def compare[T : Ordering : Manifest](a: AnyRef, b: AnyRef) = {
val c = manifest[T].erasure
if (c.isAssignableFrom(a.getClass) && c.isAssignableFrom(b.getClass))
implicitly[Ordering[T]].compare(a.asInstanceOf[T], b.asInstanceOf[T])
else
throw new IllegalArgumentException("Wrong argument type")
}
And then use it like this:
compare[Date](new Date, new Date)
compare[String]("A", "B")
But this code will throw IllegalArgumentException
:
compare[Date]("A", "B")
If you really don't know types of objects, that you are trying to compare, then you can use this solution:
def compare(a: AnyRef, b: AnyRef) = {
val c = classOf[Comparable[_]]
if (c.isAssignableFrom(a.getClass) && c.isAssignableFrom(a.getClass) && a.getClass == b.getClass) {
a.asInstanceOf[Comparable[AnyRef]].compareTo(b.asInstanceOf[Comparable[AnyRef]])
} else {
throw new IllegalArgumentException("Incopatible argument types: " + a.getClass.getName + " and " + b.getClass.getName)
}
}
It falls down to Java's Comparable
interface. Generally scala has 2 traits for this purpose:
Ordred
- similar to Comparable
, but existing classes (like String
or Date
) do not implement it, so you can't check it at runtime (at least for these classes)Ordering
- it's type class, and you can't retrieve it at runtime.From the other hand Ordered
extends Comparable
interface, so this solution should also work for all classes that extend Ordered
.
Upvotes: 6
Reputation: 421310
How about something like this?
scala> (i, j) match {
| case (a: Ordered[Any], b: Ordered[Any]) => a < b
| case _ => throw new RuntimeException
| }
Upvotes: 0