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