From: Lew on 1 Jun 2010 19:07 Lew wrote: >>>> 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. Daniel Pitts wrote: >>> 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. Arved Sandstrom wrote: >> 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 Pitts wrote: > 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. -- Lew
From: Daniel Pitts on 1 Jun 2010 19:50 On 6/1/2010 4:07 PM, Lew wrote: > 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. -- Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
From: Mike Schilling on 1 Jun 2010 21:55 "Robert Klemme" <shortcutter(a)googlemail.com> wrote in message news:86krebFekoU1(a)mid.individual.net... > On 31.05.2010 21:58, Mike Schilling wrote: >> Tom Anderson wrote: >>> On Mon, 31 May 2010, Robert Klemme wrote: >>> >>>> On 31.05.2010 18:57, Tom Anderson wrote: >>>>> On Mon, 31 May 2010, Lew wrote: >>>>> >>>>>> Tom Anderson wrote: >>>>>>> if ((obj == null) || !(obj instanceof SearchResultHotels)) return >>>>>>> false; >>>>>> >>>>>> The '(obj == null)' clause is superfluous. >>>>> >>>>> Good point. >>>>> >>>>> My brain, for some reason, has a hard time remembering that: >>>>> >>>>> SearchResultHotels x = (SearchResultHotels)null; >>>>> >>>>> is okay but: >>>>> >>>>> null instanceof SearchResultHotels >>>>> >>>>> is false. >>>> >>>> You just need to remember that null does not have a type. At least >>>> that's what helped me to get this straight. :-) >>> >>> Yes, when i think about it, it's all perfectly clear. But i get it >>> wrong when i'm not thinking about it. >> >> Me too. Especially since the usage >> >> if (x instanceof Type) >> { >> Type t = (Type)x; >> ... >> >> is so common. The instanceof check (among other things) avoids a cast >> failure, but the cast would work perfectly well if x were null. > > 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.
From: Jim Janney on 3 Jun 2010 13:56 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(). 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. -- Jim Janney
From: Arved Sandstrom on 3 Jun 2010 16:51
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. > 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) |