Andres
Andres

Reputation: 1454

Cast objects to comparable type

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

Answers (2)

tenshi
tenshi

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") 

Update

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

aioobe
aioobe

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

Related Questions