From: Andreas Leitgeb on
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
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
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
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
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 |