[SalesForce] System.ListException: One or more of the items in this list is not Comparable

I have an interface, MyInterface, that extends Comparable since I want to be able to sort lists of these objects:

  1 global interface MyInterface
  2        extends Comparable {

All classes that implement MyInterface contain this code to implement the compareTo method:
(Unfortunately these classes are extending different superclasses, and multiple inheritance isn't possible with Apex)

  1 global class SubClass1
  2        extends SuperClass1
  3        implements MyInterface
  4        {

127     public Integer compareTo( Object OtherRecord ){
128         MyInterface OtherMyInterface = (MyInterface) OtherRecord ;
129         if ( this.getTimestamp() > OtherMyInterface.getTimestamp() ) return 1;
130         if ( this.getTimestamp() < OtherMyInterface.getTimestamp() ) return -1;
131         else return 0 ;
132     }

A Visualforce controller is trying to sort the these MyInterface objects, but it is failing with a run-time exception:

System.ListException: One or more of the items in this list is not Comparable

 61         /*
 62         for (MyInterface s : MyList){
 63             System.debug( s instanceOf Comparable );
 64         }
 65         */ 
 66         MyList.sort();

Attempts to uncomment lines 61-64 fail with a compile time exception:

Operation instanceof is always true since an instance of MyInterface is always an instance of System.Comparable


Does anyone out there have any ideas on what I'm missing here? How is it that one of the objects is not Comparable if all of them are instances of Comparable?

Best Answer

There's a subtle bug involved here, which I was able to replicate with the following execute anonymous:

interface MyInt extends Comparable {
}
class SuperC implements MyInt {
    public Integer compareTo(Object o) {
        return 0;
    }
}
class SubC extends SuperC {

}
SuperC[] items = new SuperC[0];
items.add(new SubC());
items.add(new SuperC());
items.sort();

You can fix this by adding Comparable to the sub-class:

interface MyInt extends Comparable {
}
class SuperC implements MyInt {
    public Integer compareTo(Object o) {
        return 0;
    }
}
class SubC extends SuperC implements Comparable {

}
SuperC[] items = new SuperC[0];
items.add(new SubC());
items.add(new SuperC());
items.sort();

Note that SubC will still be considered to be a MyInt as well, so you can mix and match as you need to.

Note that, while you can't extend from multiple classes, it's legal to implement multiple interfaces:

class SubC extends SuperC implements MyInt, Comparable {
}

You can use this to work around the problem for now, but ideally we should have someone look into why Apex Code behaves this way to begin with.