Prev: Call for Papers: International Conference on Internet and Multimedia Technologies ICIMT 2010
Next: Is there a 'Filter' or 'Predicate' interface anywhere in theJDK?
From: Andreas Leitgeb on 25 Jun 2010 05:28 Simon Brooke <stillyet+nntp(a)googlemail.com> wrote: > On Thu, 24 Jun 2010 12:45:02 +0000, Andreas Leitgeb wrote: >> Eric Sosman <esosman(a)ieee-dot-org.invalid> wrote: >>> On 6/23/2010 5:27 PM, Daniel Pitts wrote: >>>> [... using getClass() in equals() ...] Actually, I would use: >>>> if (other == this) { return true; } >>>> if (other == null || other.getClass() != getClass() { return false; } >>> Hmm. I usually write >>> if (other == null || other.getClass() != Thing.class) >>> Is there a reason to prefer one or the other? >> I'm rather surprised to see .equals() being called an exceptional >> usecase for exact class-check. >> From previous discussions here and elsewhere, I had gathered, that >> the "really correct" way to handle (non-trivial!) .equals() in a class >> hierarchy would be to make all non-leaf-classes abstract. > Making all non-leaf classes abstract is an example of poor design. Maybe, you just missed one constraint that I mentioned: My comment about abstract non-leaf-classes was constrained to hierarchies, that define their custom .equals() in a way that seems to require exact class-check. (My previous statement was in itself more general but it was in the context of needing direct class-check, so it was still correct in the given context) It would indeed make no sense at all, to apply my comment generally to all hierarchies. > [Bird, Penguin extends Bird - should Bird be abstract?] Actually, you won't ever find a real instance of Bird in nature that isn't really of some more specific class. Be it Hawk, Craw, Ostrich, Turkey, Chicken, ... > Are you saying that class Bird ought not to be instantiable? If (AND ONLY if) you were to define some *finer* equality for Penguin than you did for Bird, then my claim applies. More precisely, equal and inheritence work well, as long as the subclass's .equal() is "equal or coarser" than the superclass's. Everything is "equal or coarser" than Object's .equals(). The opposite of coarser happens with classes like (partially pseudocode) class Circle { int radius; ... equals(o) { radius==o.radius;} } class ColoredCircle extends Circle { int color; ... equals(o) { super.equals(o) && color==o.color;} } ColoredCircle's .equals() is now finer than Circle's. That's where problems creep in. To solve them, either you resort to reflection by checking exact class (imho: bad design), or you make sure, that no direct Circle-instances can exist, and instead define an "UncoloredCircle" as a separate leaf-class.
From: Tom Anderson on 25 Jun 2010 14:32 On Fri, 25 Jun 2010, Simon Brooke wrote: > On Thu, 24 Jun 2010 12:45:02 +0000, Andreas Leitgeb wrote: > >> Eric Sosman <esosman(a)ieee-dot-org.invalid> wrote: >>> On 6/23/2010 5:27 PM, Daniel Pitts wrote: >>>> [... using getClass() in equals() ...] Actually, I would use: >>>> if (other == this) { return true; } >>>> if (other == null || other.getClass() != getClass() { return false; } >>> Hmm. I usually write >>> if (other == null || other.getClass() != Thing.class) >>> Is there a reason to prefer one or the other? >> >> I'm rather surprised to see .equals() being called an exceptional >> usecase for exact class-check. >> >> From previous discussions here and elsewhere, I had gathered, that >> the "really correct" way to handle (non-trivial!) .equals() in a class >> hierarchy would be to make all non-leaf-classes abstract. > > Making all non-leaf classes abstract is an example of poor design. On the contrary, it's a sign of well-factored code. It's not an iron rule, but in general, if you have concrete classes extending other concrete classes, there are abstractions you haven't identified. > public class Bird { > public boolean getCanFly() { > return true; > } > } > > public class Penguin extends Bird { > public boolean getCanFly() { > return false; > } > } > > Are you saying that class Bird ought not to be instantiable? Are you > saying I ought to add a class: > > public class InstantiableBird extends Bird {} ? > > which has no new semantic content, which overrides or specialises > nothing, and that's 'really correct'? In this example, it's hard to say, because modelling kinds of birds as an inheritance hierarchy is itself not good OO design. The idea of mapping zoological hierarchies onto executable ones is - if you'll excuse the expression - a canard. This would be a time to use the Type Object pattern, and push the taxonomy out into a set of flyweight instances of a BirdType class. But sticking with the example, yes, you should pull out more classes: Bird FlyingBird Swallow AfricanSwallow EuropeanSwallow FlightlessBird Penguin With the obvious abstract and concrete methods. tom -- Thinking about it, history begins now -- sarah
From: ClassCastException on 25 Jun 2010 20:53 On Fri, 25 Jun 2010 09:28:16 +0000, Andreas Leitgeb wrote: > Simon Brooke <stillyet+nntp(a)googlemail.com> wrote: >> [Bird, Penguin extends Bird - should Bird be abstract?] > Actually, you won't ever find a real instance of Bird in nature that > isn't really of some more specific class. Be it Hawk, Craw, Ostrich, > Turkey, Chicken, ... Misspellings like that really stick in my crow... :-)
From: Martin Gregorie on 26 Jun 2010 12:21 On Sat, 26 Jun 2010 11:53:23 -0400, Arne Vajhøj wrote: > > I would even say that #3 is sometimes practical, but it is not good OOP. > Then the geometric drawing example that's often seen in teach-yourself Java and C++ books where Point is defines as a concrete base class and then extended extended to form Circle, Ellipse, Rectangle, Triangle, .... classes shouldn't really be used because its bad OOP? However, I don't think Bird is a particularly good example simply because almost all case I can think of where I'd might be interested in using it would compare birds across species in ways that would require the same attributes in all instances, so extensions simply wouldn't arise, particularly if the attributes flightless, aquaticSpecies and (possibly) diver were used. -- martin@ | Martin Gregorie gregorie. | Essex, UK org |
From: Martin Gregorie on 26 Jun 2010 17:14
On Sat, 26 Jun 2010 13:09:25 -0400, Arne Vajhøj wrote: > On 26-06-2010 12:21, Martin Gregorie wrote: >> On Sat, 26 Jun 2010 11:53:23 -0400, Arne Vajhøj wrote: >>> I would even say that #3 is sometimes practical, but it is not good >>> OOP. >> Then the geometric drawing example that's often seen in teach-yourself >> Java and C++ books where Point is defines as a concrete base class and >> then extended extended to form Circle, Ellipse, Rectangle, Triangle, >> .... classes shouldn't really be used because its bad OOP? > > I assume that you mean Figure and not Point as base class. > Unfortunately not: "Data Abstraction and Object-Oriented Programming in C++" by Gorlen,Orlow and Plexico uses Point as components within Line and Circle classes though without explicit inheritance: I don't read C++ well enough to understand much more than this, but I think there's no inheritance and no abstract base class. However, Ivor Horton's "Beginning Java" does better: I misremembered what it said. It uses a utility Point class but bases its shapes on an abstract Element base class which only has a colour attribute. >> However, I don't think Bird is a particularly good example simply >> because almost all case I can think of where I'd might be interested in >> using it would compare birds across species in ways that would require >> the same attributes in all instances, so extensions simply wouldn't >> arise, particularly if the attributes flightless, aquaticSpecies and >> (possibly) diver were used. > > A lot depends on the context. > True enough, though a Bird with as species attribute would be very useful since it could be used for anything from building an experimental results database for a study of avian flight performance to building a cladistic species descent tree. Doing either would be harder if Bird was merely an abstract base class. -- martin@ | Martin Gregorie gregorie. | Essex, UK org | |