Map question

L

Lew

Lew said:
Arved said:
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.

Precisely so.

Daniel said:
Perhaps a "Timing" object, which has a toString() which returns time in
ms/s/minutes/etc..., but is not a value type (eg, identity is important).

But then you'd likely want the object ID of the particular 'Timing' object in
order to tell its timing information apart from that of other 'Timing' object,
wouldn't you?
The object is textually represented, but equals/hashCode are not
relevant to the contents of the textual representation.

Yes, they are, on the usual need to know which 'Timing' object you are
representing by 'toString()'.

You might pick something arbitrary not exactly the same as the object ID, but
what you pick had durned well better be consistent with the ID.

I can think of corner cases where 'toString()' wouldn't need to identify the
object it represents, but they are tortuous at best and violate the spirit of
'toString()': to provide a textual representation of the object, i.e., a
string that identifies the object. If that is the purpose of 'toString()',
and to a first order of approximation that is the purpose of 'toString()',
then the text must be consistent with the characteristics of the object that
identify it.

Violate at your peril.

The novice doesn't know the rules. The professional knows the rules by heart.
The virtuoso knows when to break the rules. The master creates the rules.
 
D

Daniel Pitts

Lew wrote:
The novice doesn't know the rules. The professional knows the rules by
heart. The virtuoso knows when to break the rules. The master creates
the rules.
Careful with that. Novices create rules too, they just don't realize it.
 
M

Mike Schilling

Robert Klemme said:
But then you'd get a NPE as soon as you try to invoke any method on the
reference - so the idiom totally makes sense and the instanceof check
avoids a cast failure *and* a NPE.

Assuming you're going to invoke a method on it, rather than pass it as a
parameter to something that does a null check (or accepts nulls). But the
current behavior is still the most useful one 80-90% of the time, I'd say.
 
J

Jim Janney

Arved Sandstrom said:
Daniel said:
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().

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.
 
A

Arved Sandstrom

Jim said:
Arved Sandstrom said:
Daniel said:
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.
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()?

AHS

--
These people are still programming in terms of training wheels.
I kind of get scared. If we're really a profession,
someone who needs to put in those kinds of comments
should not be allowed to touch code that's going to ship.

Jim Coplien on misuse of design patterns
(http://www.infoq.com/interviews/coplien-dci-architecture)
 
J

Jim Janney

Arved Sandstrom said:
Jim said:
Arved Sandstrom said:
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.
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.
 
M

Mike Schilling

Jim Janney said:
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?")
 
A

Arved Sandstrom

Jim said:
Arved Sandstrom said:
Jim said:
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().
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
 
M

Mike Amling

Arved said:
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
 
L

Lew

Think "candidate key".

Mike said:
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.
 

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,777
Messages
2,569,604
Members
45,211
Latest member
NelleWilde

Latest Threads

Top