In the entry about object schizophrenia I used
java.lang.Comparable as an example in J#, but for IKVM I did not mention it as a ghost interface. In the comments Stuart Ballard asked why Comparable isn't a ghost interface.
Unlike what Stuart claimed, this is definitely not a stupid question. He also figured out part of the answer:
java.lang.Comparable maps to
That's not the whole story though. The reason that I originally mapped
IComparable was that
System.String conveniently implements
IComparable and that
IComparable.CompareTo is semantically (nearly) identical to
Comparable.compareTo. Back then I hadn't yet "invented" the ghost interface idea and this seemed to solve most of the issues (the other two ghost interface candidates,
Serializable are only used as marker interfaces, so it didn't seem like a big deal that
System.String didn't implement these interfaces.
java.lang.CharSequence only appeared in Java 1.4 and I vaguely knew about it, but at the time I chose not to worry about that yet.)
A nice side effect of mapping
IComparable is that you get better interop (e.g. Java objects that implement
Comparable will sort correctly when used in .NET applications and .NET objects that implement
IComparable will sort correctly in Java), so that meant that when I developed ghost interfaces I didn't really want to go back and change
Comparable into a ghost interface.
Finally, there is one more complication. Even though
IComparable.CompareTo have identical semantics, there still is a problem with
String.compareTo is specified more strictly than
Comparable.compareTo. The interface method is specified to simply return zero or a signed or unsigned integer, but the
String version is actually specified to return the difference between the mismatching characters (or zero, if the strings match.) To handle this correctly, when you call
Comparable.compareTo, you're actually calling a static method
Comparable.__Helper.compareTo that first does a check to see if the object you're comparing is a
String and, if so, it calls a static helper method that implements the specified Java comparision algorithm.
BTW, the reason that the static compareTo helper method lives inside a nested __Helper class is because Reflection.Emit (on .NET 1.x) incorrectly prohibits adding static methods to interfaces (which is entirely legal according to the CLI specification).
The following table compares the direct methods calls with the interface method calls. Note that these basically represent a worst case estimate, because of limit amount of work the actual compareTo method does. Note also that for notational convenience I used the zero digit, but in the actual benchmark I used a local variable containing
These results are on .NET Framework 2.0 (x86). Averaged over 10,000,000 calls and includes the loop overhead.
For comparison, here are the results for JDK 1.5 HotSpot Client VM: