Should equals() and compareTo() be equivalent to test for equality ??

N

Neroku

Well, I know equals() and compareTo() could behave different to test
for equality, it just depend on the way I implement them, but, Would it
be a bad practice to rewrite equals() and compareTo() so they behave in
the following way:

- Two different instances of the same class hold different attribute
values, calling equals() return false comparing both objects because
they are not the same, but compareTo() return 0, since this is the
sorting criteria I want (a desired attribute match).

or even

- Two different objects of the same class hold the same attribute
values, this is, they are internally equals, and calling equals()
return false because the are different instances (the references are
not the same), but calling compareTo() return 0, since all attributes
contain the same value.


Thanks in Advanced
 
I

Ingo Menger

Well, I know equals() and compareTo() could behave different to test
for equality, it just depend on the way I implement them, but, Would it
be a bad practice to rewrite equals() and compareTo() so they behave in
the following way:

Sure. No matter how you define equality, the following should always
hold:
a.equals(b) == (a.compareTo(b) == 0)

Note that certain standard classes deviate from this ideal, i.e.
BigDecimal.
 
G

Gordon Beaton

Well, I know equals() and compareTo() could behave different to test
for equality, it just depend on the way I implement them, but, Would it
be a bad practice to rewrite equals() and compareTo() so they behave in
the following way:

To test for identity (i.e. reference equality), use ==, not equals().

I would find it extremely confusing if compareTo() returned 0,
indicating that the elements are equal in sort order, but equals()
returned false. If the objects represent the same *value*, then they
are *equal*.

/gordon
 
T

Tom Hawtin

Neroku said:
Well, I know equals() and compareTo() could behave different to test
for equality, it just depend on the way I implement them, but, Would it
be a bad practice to rewrite equals() and compareTo() so they behave in
the following way:

The JavaDocs and I strongly recommend that compareTo be consistent with
equals (and hashCode). In theory it shouldn't actually make any
difference (other than for one of the concurrent collections in 1.5 (not
1.6)). However, as a programmer, I would find it 'surprising'.

IMO, natural ordering should be considered an implementation artifact.
String is Comparable, for instance, but the order makes no sense. It
sorts case sensitive, and doesn't even account for code points above
0x10000.
- Two different instances of the same class hold different attribute

The value of the fields are irrelevant. Try to think in terms of what
the object actually represents.

Tom Hawtin
 
I

Ingo Menger

IMO, natural ordering should be considered an implementation artifact.
String is Comparable, for instance, but the order makes no sense.

It's not supposed to.
It sorts case sensitive,

Yes, that's because it's supposed to be well defined, and this means,
for instance, that "WELL DEFINED" must be either greater or less than
"well defined", since it's not equal. But it can't be equal, because it
can be observed, that it's different.
(One could make this observation impossible by assigning upper case
letters the same code points as lower case letters, of course. I don't
think this would not be very practical, to say the least.)
and doesn't even account for code points above
0x10000.

Is that so?
That's bad, of course. But I think most people really don't care about
those.
After all, for many decades, it didn't account for code points above
0xff. And it was not that bad.
 
C

Chris Uppal

Neroku said:
Well, I know equals() and compareTo() could behave different to test
for equality, it just depend on the way I implement them, but, Would it
be a bad practice to rewrite equals() and compareTo() so they behave in
the following way:

- Two different instances of the same class hold different attribute
values, calling equals() return false comparing both objects because
they are not the same, but compareTo() return 0, since this is the
sorting criteria I want (a desired attribute match).

I would say that in general it's a bad idea for compareTo() not to be
compatible with equals(). As others have said, it's not what they'd expect to
see, and that's always something to avoid if you can.

There may be sufficient reasons to break that rule (though I can't think of an
example off the top of my head). Remember that you have the option of using a
custom Comparator for your objects instead of the natural ordering implied by
compareTo(). If the "odd" comparison order is particularly natural (despite
it's oddness ;-) or likely to be needed in several places, then I would make
the special Comparator implementation a class statically nested within the main
object class. Quite possibly the Comparator would be stateless in which case
you could have a single, immutable, public instance of the Comparator available
for convenient use.

-- chris
 
A

Andreas Leitgeb

Gordon Beaton said:
To test for identity (i.e. reference equality), use ==, not equals().

I would find it extremely confusing if compareTo() returned 0,
indicating that the elements are equal in sort order, but equals()
returned false. If the objects represent the same *value*, then they
are *equal*.

100% agree.

If the originator of this threads really needs an ordering
that is inconsistent with .equals(), there is also the path
of deriving a class from "Comparator", and pass that
to most of the sorting-methods offered by the Class
library. IOW, most methods that depend on an ordering
have an overloaded variant that accepts a separate
Comparator.
 
T

Tom Hawtin

Ingo said:
It's not supposed to.

Yes. I'm trying to say that there is no point attempting to make the
natural order make any sense.

Whilst you might make a Comparator differ from equals (the JavaDocs say
use caution), it doesn't matter with Comparable. Give it any old order.
The natural order is for algorithms such as TreeSet, not to define an
ordering for presentation purposes. Making compareTo give a meaningful
result is like trying to do the same with hashCode.

Tom Hawtin
 
I

Ingo Menger

The natural order is for algorithms such as TreeSet, not to define an
ordering for presentation purposes. Making compareTo give a meaningful
result is like trying to do the same with hashCode.

Exactly, apart from numbers, where the meaning is the mathematical one.
 
T

Tom Hawtin

Tor said:
Countercase: You have a Customer class you want to sort (the function
of Comparable) by last name then first name. And then you get two
customers called Joe Jackson. But you use a persistence framework so
you need to use equals() and hashCode() on some unique key (like a
customer number). So equals() will return false for the two Joes, but
compareTo() will return 0.

It's a bad idea to use natural ordering for presentation. Use a
Comparator instead.

If you put your customers in a TreeSet (with natural ordering), you
wouldn't get them all back out.

Tom Hawtin
 
T

Tor Iver Wilhelmsen

Gordon Beaton said:
I would find it extremely confusing if compareTo() returned 0,
indicating that the elements are equal in sort order, but equals()
returned false. If the objects represent the same *value*, then they
are *equal*.

Countercase: You have a Customer class you want to sort (the function
of Comparable) by last name then first name. And then you get two
customers called Joe Jackson. But you use a persistence framework so
you need to use equals() and hashCode() on some unique key (like a
customer number). So equals() will return false for the two Joes, but
compareTo() will return 0.

You could probably add a third sorting field as a "tie breaker",
though.
 
T

Tor Iver Wilhelmsen

Tom Hawtin said:
It's a bad idea to use natural ordering for presentation. Use a
Comparator instead.

Strange when the Javadocs for Comparable and Comparator seem almost
copy-pasted... so Comparator's intent seems to be an "outside" version
of Comparable.
If you put your customers in a TreeSet (with natural ordering), you
wouldn't get them all back out.

Well, a TreeSet with a Comparator has the same issue.

The natural ordering of named objects would seem to be alphabetical.
It's not the sorting algorithm's problem that people foolishly are
allowed to have the same name. :)

But a fix would be to assume this in the sorting and thus add a
"unseen" sorting key, like the customer number in my example.
 
P

Patricia Shanahan

Tor said:
Strange when the Javadocs for Comparable and Comparator seem almost
copy-pasted... so Comparator's intent seems to be an "outside" version
of Comparable.


Well, a TreeSet with a Comparator has the same issue.

The natural ordering of named objects would seem to be alphabetical.
It's not the sorting algorithm's problem that people foolishly are
allowed to have the same name. :)

But a fix would be to assume this in the sorting and thus add a
"unseen" sorting key, like the customer number in my example.

How about the numeric case. Should BigDecimal 5 with a scale of 3 be
greater or less than BigDecimal 5 with scale 7?

The problem in this case is two numbers that are equal in the sense of
having the same magnitude, but that round differently.

Patricia
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top