How to check if object is an instanceof a class, but not a sub-class?

L

Lew

Tom said:
You mean both of them? Then you either have to introduce a common base
class ParallelRightQuadrilateral, or be unable to write code that
manipulates boxes uniformly. Making Square a subtype of Rectangle is still
very attractive from a programmer-friendliness point of view. Immutability
is one way of overcoming the problems that introduces - and it really does
solve them. Squares are only non-Rectangular when they'r mutable, because
it's only their mutability that is not a superset of Rectangle's

Oh, yeah. You're right.
 
E

Eric Sosman

On 25-06-2010 04:07, Simon Brooke wrote:
[...]
Are you saying that class Bird ought not to be instantiable?

Yes.

There are no bird instances in the real world. They are all
instances of some type of bird.

That way lies madness. There are no Parrot instances in
the real world, only Polly and Snoofles and FeatheredBastard and
so on.

Why aren't those instances of Parrot?

I was trying to follow Arne Vajhøj's position "There are no bird
instances in the real world. They are all instances of some type of
bird" to an absurd consequence, thereby casting doubt on it. By
"that way lies madness," I meant that refusal to generalize dooms
every model but one to failure. (The one exception exists, but is
rather difficult to comprehend; centuries of debate have not fully
explained the Programmer's purposes, nor even proved his sanity.)
Eventually, every practical model must consider N distinct entities
and say "These are all Parrots" or "These are all Birds" or "These
are all CarbonBasedLifeForms." The much-discussed "real world" is
not subject to this built-in crudification of detail -- but the MDRW
doesn't have "classes" at all, merely individuals. ("Individual what?"
is a question I'd prefer to leave to the philosophers; as a computer
person, I can see to it that they'll starve.)
 
A

Arne Vajhøj

A problem that goes away when you make the durn things immutable.

Not completely.

Methods that return a new modified instance would still have
some weird behavior.

Arne
 
A

Arne Vajhøj

Depends on the signature of the method and its precise behavior.

It's debatable whether one really needs methods in the type that return
modified versions of the original. But assuming one does,

It is rather common to have such. The Java API itself has some
important ones.
the method
could easily enforce Rectangles and Squares, either by throwing
exceptions if misused (which is actually possible even with mutable
types, though would involve more work), or by providing methods that
always return the right kind of type (Square if the new dimensions are
equal, Rectangle otherwise).

What should the formal return type be?

The sub class can return the super class but not the
other way around.
There's no reason for weird behavior to exist. Just don't implement
weird behavior. :)

Difficult to avoid if the classes should have rich functionality.

Arne
 
A

Arne Vajhøj

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.

Many geometric figures would contain points as members (corners,
center etc.) - that is not quite the same as extending.
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.

I assume that is something like my Figure class.
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.

Oh yes.

But often the discussion about class hierarchy becomes a lot
easier when you have a specific context. Often the domain
logic / business rules / whatever they are called make it
rather obvious what to do.

Arne
 
C

ClassCastException

Arne said:
[...]
It's debatable whether one really needs methods in the type that
return modified versions of the original. But assuming one does,

It is rather common to have such. The Java API itself has some
important ones.

Really? Where is the Square type in the Java API that inherits
Rectangle, never mind the immutable version that returns modified
versions of the original?
What should the formal return type be?

Whatever you want it to be. One option is Rectangle. If it matters
whether the resulting type is a Square (e.g. Rectangle.FitInSquare()),
you can check and cast.

If you want the return type to be Square, you have to throw an exception
if someone tries to return a non-Square from a Square. Or you provide
an API that only returns a Square (e.g. adjusts both dimensions by
identical amounts).
The sub class can return the super class but not the other way around.

Rectangle can return a Square instance and Square can return a
Rectangle. I have no idea why you think you can't do it that way.

Of course, whatever API is chosen, it needs to make sense in context.
But there's no fundamental reason Rectangle can't return a Square.
Difficult to avoid if the classes should have rich functionality.

Now you are adding requirements not originally stipulated. No one said
anything about "rich functionality", nor is it even clear what is meant
in the case of the Square/Rectangle example.

Pete

How about making the example more concrete, then.

public class Rectangle {
protected final double l;
protected final double t;
protected final double w;
protected final double h;

public Rectangle (double left, double top, double width,
double height) {
if (width <= 0.0) throw new IllegalArgumentException();
if (height <= 0.0) throw new IllegalArgumentException();
l = left; t = top; w = width; h = height;
}

// getters go here, and getRight and getBottom

public Rectangle getScaledInstance (double scaleFactor) {
if (scaleFactor == 0.0) throw new IllegalArgumentException();
// top left corner is center of scaling transform's effect
if (scaleFactor < 0.0)
return new Rectangle(l + w*scaleFactor, t + h*scaleFactor,
-w*scaleFactor, -h*scaleFactor);
return new Rectangle(l, t, w*scaleFactor, h*scaleFactor);
}

public Rectangle getWithWidth (double newWidth) {
if (newWidth <= 0.0) throw new IllegalArgumentException();
return new Rectangle(l, t, newWidth, h)
}

public Rectangle getWithHeight (double newHeight) {
if (newHeight <= 0.0) throw new IllegalArgumentException();
return new Rectangle(l, t, w, newHeight)
}

public Rectangle getMoved (double newLeft, double newTop) {
return new Rectangle (newLeft, newTop, w, h);
}
}

public class Square extends Rectangle {
public Square (double left, double top, double size) {
super(left, top, size, size);
}

public Square getScaledInstance (double scaleFactor) {
if (scaleFactor == 0.0) throw new IllegalArgumentException();
// top left corner is center of scaling transform's effect
// w = h = size
if (scaleFactor < 0.0)
return new Square(l + w*scaleFactor, t + h*scaleFactor,
-w*scaleFactor);
return new Square(l, t, w*scaleFactor);
}

public Square getMoved (double newLeft, double newTop) {
return new Square (newLeft, newTop, w);
}
}

The "copy-mutator" methods that would preserve squareness return Squares.
The ones that could produce non-square rectangles aren't even overridden,
and return Rectangles. This works, though it's possible to get square
Rectangles that are not Squares. Making the constructor protected, adding
a public factory method that calls it normally but only after if (width
== height) return new Square(left, top, width);, and changing the "copy-
mutators" to call this factory method would address this, if one felt it
necessary.

Of course if there's any problem with the above let me know and I'll try
to address it.
 
A

Andreas Leitgeb

Lew said:
I forgot to mention that Bird implements List<Bird>. Weird, but there you
go.
[...] Besides, it's not true that a bird in
the hand is *equal to* two in the bush, it's that a bird in the hand
is *worth* two in the bush.

The German variant of that proverb would amount to:

hand.getTheSparrow().preferenceLevel() > roof.getTheDove().preferenceLevel()

PS: I wouldn't trade a bird in my hand even for three birds in the bush...
 

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,776
Messages
2,569,603
Members
45,197
Latest member
ScottChare

Latest Threads

Top