11

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?

2
  • can you post how getTimeStamp is defined? Can any errors appear there?
    – kurunve
    Commented Mar 5, 2018 at 8:17
  • 1
    @kurunve it's defined in the interface as DateTime getTimeStamp();. Each class has it's own implementation, but that isn't causing any trouble. I've gotten the code work at least, and it looks like the Comparable interface needs to also be explicitly listed in each class that implements MyInterface. It seems like the compiler thinks that what I have here is sufficient, but the runtime is having trouble finding what it needs.
    – martin
    Commented Mar 5, 2018 at 8:24

1 Answer 1

10

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.

2
  • 1
    Someone having premiere can raise a case with SF and get them investigate this deeply. Its bit weird, in JAVA 8 this gets compiled and run successfully, If am not wrong SF being built with JAVA 8 should be able to handle this. Commented Mar 5, 2018 at 10:24
  • 3
    @PranayJaiswal I've left a message in the MVP channel for the Apex Code PM. Failing that, I do have Premier Support, and can submit a case as well.
    – sfdcfox
    Commented Mar 5, 2018 at 10:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .