Consider enhancing Comparable with lessThan(), greaterThan() and friends

Stuart Marks stuart.marks at oracle.com
Fri Apr 22 00:35:17 UTC 2022


Yes, this has been proposed before. See

     https://bugs.openjdk.java.net/browse/JDK-8241056

It's not obviously a bad idea, but there are a bunch of costs that seem to 
counterbalance the benefits.

I think the biggest problem is that adding a bunch of default methods to a 
widely-implemented interface (Comparable) runs the risk of name clashes. An 
alternative would be to add static methods with nice names, but I'm still not sure 
it's worthwhile.

Perhaps the next biggest problem is that it adds a lot of clutter to the API, and it 
doesn't add any new abstractions, it doesn't strengthen any existing abstraction, it 
doesn't increase performance of anything, etc. It arguably improves readability, but 
it also arguably could lead to confusion.

Personally I don't find `if (object.compareTo(other) > 0)` objectionable. Just move 
the comparison operator between the two operands. Then again, I'm an old C hacker 
who grew up with `if (strcmp(a, b) > 0)` which is basically the same thing, so I'm 
used to it.

(Interestingly, I looked at a bunch of Java tutorial sites, and -- setting aside 
their mistakes -- they all talked about how to *implement* Comparable, and how use 
Comparable objects for sorting, but not about how to compare the return value 
against zero to compare two objects. The javadocs don't explain this either. So 
maybe we have a documentation problem.)

Named methods and their alternatives seem to be something along the lines of:

     if (object.greaterThan(other))
     if (object.isGreaterThan(other))
     if (object.gt(other))

(Choice of names deferred to a bike shed to be had at a later time.)

This is kind of ok, until we get to Comparator, which would need the same thing. 
Instead of

     if (c.compare(a, b) > 0)

we might want

     if (c.greaterThan(a, b))
     if (c.isGreaterThan(a, b))
     if (c.gt(a, b))

Here we have to do the same mental gymnastics of moving the operator between the 
operands. This doesn't seem all that helpful to me.

There's also the difference between equals() and comparesEqual() or whatever. Worse, 
something like isNotEquals() is *not* the inverse of equals()! I think adding such 
methods could increase confusion instead of reducing it.

While the idiom of comparing the return value of compareTo() against zero is pretty 
cryptic, I think trying to solve it by adding a bunch of named methods somewhere 
potentially runs into a bunch of other problems. Maybe these can be avoided, but it 
seems like a lot of effort for not much gain. Maybe it would be more fruitful to 
find better ways to teach people about the compare-against-zero idiom.

s'marks




On 4/21/22 1:15 AM, Petr Janeček wrote:
> Hello,
> I'm pretty sure this must have come up a few times now, but
> I was unable to find a discussion anywhere, so here goes:
> 
> The `if (object.compareTo(other) > 0)` construct for Comparables,
> while it works, is an annoyance to readers, and I often have to
> do a double-take when seeing it, to make sure it says what I think
> it says.
> 
> Did we ever consider adding human-friendly default methods
> to Comparable like e.g. these (names obviously subject to change):
> 
> ```java
> public default boolean lessThan(T other) {
>      return compareTo(other) < 0;
> }
> 
> public default boolean lessThanOrEqual(T other) {
>      return compareTo(other) <= 0;
> }
> 
> public default boolean comparesEqual(T other) {
>      return compareTo(other) == 0;
> }
> 
> public default boolean greaterThanOrEqual(T other) {
>      return compareTo(other) >= 0;
> }
> 
> public default boolean greaterThan(T other) {
>      return compareTo(other) > 0;
> }
> ```
> 
> These are pure human convenience methods to make the code easier
> to read, we do not *need* them. Still, I absolutely personally
> think the simplification they'd provide is worth the cost.
> 
> Are there any problems with the proposed methods that prevent them
> to ever appear? Wise from the CharSequence.isEmpty() incompatibility
> (https://stuartmarks.wordpress.com/2020/09/22/incompatibilities-with-jdk-15-charsequence-isempty/)
> I looked at common libraries to look up potential matches, but
> did not find any. The closest thing I found was AssertJ with
> isGreaterThan(), and some greaterThan() methods with two or more
> parameters in some obscure libraries. Now, I'm sure there *will*
> be matches somewhere, and this is a risk that needs to be assessed.
> Or was it simply a "meh" feature not worth the hassle?
> 
> Thank you,
> PJ
> 
> P.S. I'm not a native English speaker, so the method names are
> up for a potential discussion if we agree they'd make our lives
> easier. I can imagine something like `comparesLessThan` or similar
> variations, too.
> 
> P.P.S. The `Comparator` interface does also come into mind as it
> could take similar methods, but I did not see a clear naming
> pattern there. I'm open to suggestions.
> 


More information about the core-libs-dev mailing list