From: Jim Janney on
Arved Sandstrom <dcest61(a)hotmail.com> writes:

> Jim Janney wrote:
>> Arved Sandstrom <dcest61(a)hotmail.com> writes:
>>
>>> Daniel Pitts wrote:
>>>> On 5/31/2010 11:18 AM, Lew wrote:
>>>>> Lew wrote:
>>>>>>> Always override 'equals()', 'hashCode()' and 'toString()' together or
>>>>>>> not at all; keep them consistent with each other. If 'Foo' implements
>>>>>>> 'Comparable<Foo>' then it must override those three, all
>>>>>>> consistent with
>>>>>>> 'compareTo(Foo)'.
>>>>> Arne Vajhøj wrote:
>>>>>> There are very good reasons to override equals and hashCode together.
>>>>>>
>>>>>> I can see many cases where overriding toString alone makes sense,
>>>>>> because its main purpose is to make developer logging easier. And
>>>>>> often you will want to log something without it having to be
>>>>>> comparable.
>>>>> There's nothing in my advice to require loggable things to be Comparable.
>>>>>
>>>>> If you're logging information that identifies an instance, by definition
>>>>> you have to provide a string representation of the identifying
>>>>> attributes of the instance. If you aren't logging an instance's
>>>>> identifying attributes, you don't use 'toString()' in the log message.
>>>>> Ergo, 'toString()' has to include the identifying attributes of the
>>>>> instance to be useful.
>>>>>
>>>>> The identifying attributes of the instance are precisely those that
>>>>> figue in to 'equals()' and 'hashCode()', with the possible addition of
>>>>> the object identifier. Ergo, 'toString()' must be consistent with
>>>>> 'equals()' and 'hashCode()', in the sense that it must represent the
>>>>> values of the attributes that figure in to those methods.
>>>>>
>>>>> Q.E.D.
>>>> Except your premise of the purpose of toString is incorrect.
>>>> toString needn't be consistent with equals or hashCode, as it
>>>> needn't include any of the same set of information and still fulfill
>>>> its contract.
>>> From the Object.toString() Javadocs:
>>>
>>> "In general, the toString method returns a string that "textually
>>> represents" this object."
>>>
>>> [ embedded quotation in the original ]
>>>
>>> To me that supports what Lew said, that toString() ought to be
>>> _consistent_ with equals() and hashCode(). I can't think of a "textual
>>> representation" of an object that ignores the information that
>>> identifies it.
>>
>> This is conflating two very different kinds of requirement. The
>> relationship between equals() and hashcode() is sufficiently precise
>> that it's possible to write generally useful classes, most notably
>> HashMap, that rely on it. Objects that violate the contract won't
>> work correctly with HashMaps. There's nothing similar in the contract
>> for toString().
>
> There's nothing similar to that in the contract for toString(),
> no. But if you markedly deviate from using the information that also
> is used by equals(), you simply won't have a useful toString(). Other
> code won't care, but someone who has to read the log files might.

On the contrary, the toString() defined in Object may be completely
useful, if that's all you need from it. It's certainly the easiest one
to provide, and it works as well with the rest of the JDK classes as
anything else.

If you have a use case that involves toString(), for example writing
information to a log file, then write it for that use case. If you
don't have a use case, my recommendation is not to mess with
toString() at all. YAGNI.

>> One can imagine requiring that objects for which equals() returns true
>> should also return the same value for toString(), but I'm not sure
>> this would even be useful.
>>
> I think it would be a sensible thing for toString() to do. Why add the
> information that doesn't get used by equals()?

Because someone who has to read the log files might be interested in
more than that? Or you may have objects being logged that don't
redefine equals() -- object identity works well enough in many cases.

--
Jim Janney
From: Mike Schilling on
"Jim Janney" <jjanney(a)shell.xmission.com> wrote in message
news:2phbljagi1.fsf(a)shell.xmission.com...
>> I think it would be a sensible thing for toString() to do. Why add the
>> information that doesn't get used by equals()?
>
> Because someone who has to read the log files might be interested in
> more than that? Or you may have objects being logged that don't
> redefine equals() -- object identity works well enough in many cases.

There are certainly cases where I've cared about object identity ("No wonder
it's failing that way, but why the &%^$ are there two of those?")

From: Arved Sandstrom on
Jim Janney wrote:
> Arved Sandstrom <dcest61(a)hotmail.com> writes:
>
>> Jim Janney wrote:
>>> Arved Sandstrom <dcest61(a)hotmail.com> writes:
>>>
>>>> Daniel Pitts wrote:
>>>>> On 5/31/2010 11:18 AM, Lew wrote:
>>>>>> Lew wrote:
>>>>>>>> Always override 'equals()', 'hashCode()' and 'toString()' together or
>>>>>>>> not at all; keep them consistent with each other. If 'Foo' implements
>>>>>>>> 'Comparable<Foo>' then it must override those three, all
>>>>>>>> consistent with
>>>>>>>> 'compareTo(Foo)'.
>>>>>> Arne Vajhøj wrote:
>>>>>>> There are very good reasons to override equals and hashCode together.
>>>>>>>
>>>>>>> I can see many cases where overriding toString alone makes sense,
>>>>>>> because its main purpose is to make developer logging easier. And
>>>>>>> often you will want to log something without it having to be
>>>>>>> comparable.
>>>>>> There's nothing in my advice to require loggable things to be Comparable.
>>>>>>
>>>>>> If you're logging information that identifies an instance, by definition
>>>>>> you have to provide a string representation of the identifying
>>>>>> attributes of the instance. If you aren't logging an instance's
>>>>>> identifying attributes, you don't use 'toString()' in the log message.
>>>>>> Ergo, 'toString()' has to include the identifying attributes of the
>>>>>> instance to be useful.
>>>>>>
>>>>>> The identifying attributes of the instance are precisely those that
>>>>>> figue in to 'equals()' and 'hashCode()', with the possible addition of
>>>>>> the object identifier. Ergo, 'toString()' must be consistent with
>>>>>> 'equals()' and 'hashCode()', in the sense that it must represent the
>>>>>> values of the attributes that figure in to those methods.
>>>>>>
>>>>>> Q.E.D.
>>>>> Except your premise of the purpose of toString is incorrect.
>>>>> toString needn't be consistent with equals or hashCode, as it
>>>>> needn't include any of the same set of information and still fulfill
>>>>> its contract.
>>>> From the Object.toString() Javadocs:
>>>>
>>>> "In general, the toString method returns a string that "textually
>>>> represents" this object."
>>>>
>>>> [ embedded quotation in the original ]
>>>>
>>>> To me that supports what Lew said, that toString() ought to be
>>>> _consistent_ with equals() and hashCode(). I can't think of a "textual
>>>> representation" of an object that ignores the information that
>>>> identifies it.
>>> This is conflating two very different kinds of requirement. The
>>> relationship between equals() and hashcode() is sufficiently precise
>>> that it's possible to write generally useful classes, most notably
>>> HashMap, that rely on it. Objects that violate the contract won't
>>> work correctly with HashMaps. There's nothing similar in the contract
>>> for toString().
>> There's nothing similar to that in the contract for toString(),
>> no. But if you markedly deviate from using the information that also
>> is used by equals(), you simply won't have a useful toString(). Other
>> code won't care, but someone who has to read the log files might.
>
> On the contrary, the toString() defined in Object may be completely
> useful, if that's all you need from it. It's certainly the easiest one
> to provide, and it works as well with the rest of the JDK classes as
> anything else.

Picking logging as an example wasn't my greatest choice, because I
myself rarely change a toString() for logging purposes.

> If you have a use case that involves toString(), for example writing
> information to a log file, then write it for that use case. If you
> don't have a use case, my recommendation is not to mess with
> toString() at all. YAGNI.

I agree. I don't touch toString() unless I have a need for it. And it is
true enough that one subset of use cases is satisfied with the
Object.toString() default. My point is that if a person actually needs
to override then the new implementation should be consistent with
equals() and hashCode(); if not, don't use toString().

>>> One can imagine requiring that objects for which equals() returns true
>>> should also return the same value for toString(), but I'm not sure
>>> this would even be useful.
>>>
>> I think it would be a sensible thing for toString() to do. Why add the
>> information that doesn't get used by equals()?
>
> Because someone who has to read the log files might be interested in
> more than that? Or you may have objects being logged that don't
> redefine equals() -- object identity works well enough in many cases.

I prefer not to _rely_ on equals() for object identity, because often
equals() won't give me that. If I need to work with identity I use == or
as is often the case, it's a JPA situation and I have a PK. I stick with
the idea that equals() gives me a state comparison, which is effectively
what I also wish to see from toString().

AHS

--
The only way to learn a new programming language is by writing programs
in it.
--Dennis Ritchie
From: Mike Amling on
Arved Sandstrom wrote:
> Jim Janney wrote:
>> One can imagine requiring that objects for which equals() returns true
>> should also return the same value for toString(), but I'm not sure
>> this would even be useful.
>>
> I think it would be a sensible thing for toString() to do. Why add the
> information that doesn't get used by equals()?

As a counterexample, an instance may have some keyish data and some
valuish data, with an equals (and hashCode and compareTo) that depends
only on the keyish data, yet I also want to see some valuish data in
toString(). In fact, that was the case in a splay tree I implemented
yesterday.

--Mike Amling
From: Lew on
Jim Janney wrote:
>>> One can imagine requiring that objects for which equals() returns true
>>> should also return the same value for toString(), but I'm not sure
>>> this would even be useful.

Arved Sandstrom wrote:
>> I think it would be a sensible thing for toString() to do. Why add the
>> information that doesn't get used by equals()?

Think "candidate key".

Mike Amling wrote:
> As a counterexample, an instance may have some keyish data and some
> valuish data, with an equals (and hashCode and compareTo) that depends
> only on the keyish data, yet I also want to see some valuish data in
> toString(). In fact, that was the case in a splay tree I implemented
> yesterday.

Yet your 'toString()' was still consistent with 'equals()', in that you still
included the "keyish" data.

So you did the right thing there, and you can drop the "counter" from
"counterexample".

I use the word "consistent" rather loosely when it comes to 'toString()' in
that the method should *at a minimum* include the identifying information for
the instance. While that is necessary it might not be sufficient, as in
Mike's (not counter-) example.

--
Lew