Why should use of instanceof be avoided

H

HalcyonWild

Hi all,
First of all, Thanks a lot to all of you. Helped me clear up my
confusion to some extent.
I was trying out examples posted by people on this thread. I picked up
on examples given by Shakah, Thomas Weidenfeller and Dale King, and
worked upon it.

See Listing 1. I was thinking what if it is not possible to have a
common base class for the two subclasses, for example, I decide that
MyCircle and MySquare are two different classes altogether. Now I
create a MyCircle instance and a MySquare instance. And call a local
overloaded getArea() method. Whatever is passed, it recognizes the
correct call, and calls the appropriate class method to calc the area.
Note that passing MyShape instance will not work, in case you pass
MyShape and do not overload getArea() to receive MyShape parameter.
Polymorphism is one way here.

The Listing 2 changes a bit. I added getShape() method which returns
MyShape. Now MyCircle and MySquare are subclasses of MyShape. I do not
know what getShape() will return me. I can very well put MySquare
there, instead of MyCircle. And it works fine.
One dead end. I cannot modify MyCircle properties using the MyShape
ref, like setting the radius (in case i do not use the constructor to
set radius). I would need to know what shape it exactly is, so that I
know I want to change the radius or the length of the shape.

Here is one situation where you would want to use instanceof or
getClass().getName(); Let me know if I am wrong. Also let me know if
you need any clarifications. Sooner or Later, I will get back.

Listing 1.
//save in YourClass.java
public class YourClass {

public double getArea(MyCircle circle) {
return circle.calcArea() ;
}

public double getArea(MySquare square) {
return square.calcArea();
}

public static void main(String args[]) {
YourClass y = new YourClass();
MyCircle circle = new MyCircle();
MySquare square = new MySquare();
circle.setRadius(10.0);
square.setLength(10.0);
System.out.println(y.getArea(circle));
System.out.println(y.getArea(square));
}
}

class MyCircle
{
private double dRadius_;
public void setRadius(double r)
{
this.dRadius_ = r;
}
public double calcArea()
{
return (3.14159 * dRadius_ * dRadius_);
}
}

class MySquare
{
private double dLength_;
public void setLength(double l)
{
this.dLength_ = l;
}
public double calcArea()
{
return (dLength_ * dLength_);
}
}

=====================================

listing 2
public class YourClass {
public MyShape getShape()
{
MyShape shape = new MyCircle(10.0);
return shape;
}

public static void main(String args[]) {
YourClass y = new YourClass();
MyShape s = y.getShape();
System.out.println(s.calcArea());
}
}

abstract class MyShape {
public abstract double calcArea() ;
}

class MyCircle extends MyShape
{
private double dRadius_;
public MyCircle()
{
this.dRadius_ = 0.0;
}
public MyCircle(double d)
{
this.dRadius_ = d;
}
public void setRadius(double r)
{
this.dRadius_ = r;
}
public double calcArea()
{
return (3.14159 * dRadius_ * dRadius_);
}
}

class MySquare extends MyShape
{
private double dLength_;
public void setLength(double l)
{
this.dLength_ = l;
}
public double calcArea()
{
return (dLength_ * dLength_);
}
}
 
S

shakah

HalcyonWild said:
Hi all,
First of all, Thanks a lot to all of you. Helped me clear up my
confusion to some extent.
I was trying out examples posted by people on this thread. I picked up
on examples given by Shakah, Thomas Weidenfeller and Dale King, and
worked upon it.

See Listing 1. I was thinking what if it is not possible to have a
common base class for the two subclasses, for example, I decide that
MyCircle and MySquare are two different classes altogether. Now I
create a MyCircle instance and a MySquare instance. And call a local
overloaded getArea() method. Whatever is passed, it recognizes the
correct call, and calls the appropriate class method to calc the area.
Note that passing MyShape instance will not work, in case you pass
MyShape and do not overload getArea() to receive MyShape parameter.
Polymorphism is one way here.
[...stuff deleted...]

Listing 1.
//save in YourClass.java
public class YourClass {

public double getArea(MyCircle circle) {
return circle.calcArea() ;
}

public double getArea(MySquare square) {
return square.calcArea();
}

public static void main(String args[]) {
YourClass y = new YourClass();
MyCircle circle = new MyCircle();
MySquare square = new MySquare();
circle.setRadius(10.0);
square.setLength(10.0);
System.out.println(y.getArea(circle));
System.out.println(y.getArea(square));
}
}

class MyCircle
{
private double dRadius_;
public void setRadius(double r)
{
this.dRadius_ = r;
}
public double calcArea()
{
return (3.14159 * dRadius_ * dRadius_);
}
}

class MySquare
{
private double dLength_;
public void setLength(double l)
{
this.dLength_ = l;
}
public double calcArea()
{
return (dLength_ * dLength_);
}
}
[...more stuff deleted...]

Just addressing your Listing 1 example, and in particular your question
of "what if it is not possible to have a common base class for the two
subclasses". One way to deal with that in Java is to use interfaces,
e.g.:
public interface MyShape {
public double calcArea() ;
}

and changing MyCircle to something like:
public class MyCircle
implements MyShape {
private double dRadius_;
public void setRadius(double r) { dRadius_ = r; }
public double calcArea() {
return (3.14159 * dRadius_ * dRadius_);
}
}

public class MySquare
implements MyShape {
[...]
}

which gets you back to things in YourClass like:
public double getArea(MyShape s) {
return s.calcArea() ;
}

MyCircle circle = new MyCircle();
MySquare square = new MySquare();

getArea(circle) ;
getArea(square) ;

As you can tell, there are a lot of ways to slice and dice this stuff.
Using polymorphism in general, and interfaces in particular, tends to
be more tolerant of changes down the line. For instance, when a new
shape comes along (e.g. a MyRectangle), in your latest listing 1 you'd
have to add a new method to YourClass which takes a MyRectangle,
whereas in the modification above you'd just make MyRectangle implement
MyShape and everything's good-to-go.
 
T

Thomas Weidenfeller

HalcyonWild said:
The Listing 2 changes a bit. I added getShape() method which returns
MyShape. Now MyCircle and MySquare are subclasses of MyShape. I do not
know what getShape() will return me.
[...]

You are using a made-up scenario. Sure, you can't know if you get a
circle or square back from some completely alien method which just
returns shape. However, the point is to try really hard to avoid exactly
this situation. It is not always possible - we have discussed that
already - but you should try.

Let's try to apply some reasoning to your made-up scenario. This might
or might not work in the real world:

(1) Your getShape() method is basically constructed in a way as if any
kind of shape will do for the caller. The method just promises "if you
call me you get some kind of shape". For a caller this is only good
enough, if indeed any kind of shape will do for the purpose of the
caller. However, in your example it turns out it is not good enough. The
caller says "but, but, but ... if I got a circle, I want to set the
radius!".

You see the mismatch? By calling getShape() the caller indicates any
shape will do, but suddenly any shape is no longer good enough for the
caller. So, calling getShape() is already the wrong thing to do. If you
know you need a circle, *don't ask for an arbitrary shape, ask for a
circle*. The simplest way to ask for a circle is to create one:

MyCircle circleShape = new MyCircle(...);

or implement a specific getCircle method:

MyCircle circleShape = y.getCircle();
circleShape.setRadius(10);


(2) If you really need to keep the getShape() method, than one
alternative would be to once again use a double-dispatch to direct each
shape to a shape type specific configuration method:

abstract class MyShape {
abstract void config(ShapeConfigurator sc);
}

class MyCircle {
void config(ShapeConfigurator sc) {
sc.config(this);
}
}

class MyRectangle {
void config(ShapeConfigurator sc) {
sc.config(this);
}
}

// Provide shape-specific configuration
class ShapeConfigurator {
void config(MyCircle c) { c.setRadius(10); }
void config(MyRectangle r) { ... }
}

class UserShapeConfigurator extends ShapeConfigurator {
void config(MyCircle c) {
// Ask user for a new Radius and set it
...
...
}
}

ShapeConfigurator sc = new UserShapeConfigurator();
MyShape aShape = y.getShape();
aShape.config(sc);


There are for sure other architectures possible (e.g. not explicitly
providing a shape configurator), or no configurator at all, and instead
fully implement the config() methods in the shapes. It all depends on
what you really need.


/Thomas

PS: The shape/circle/rectangle/triangel/etc. example is a common one in
OO textbooks (like the pet/animal example). However, it is a dreaded
one, because as you are about to find out, the different basic geometry
shapes have very little in common (that's why the mathematicians settled
on them). There aren't too many properties one can abstract into a
superclass. E.g. even the meaning of some "origin" coordinate in the
superclass is debatable. What's the origin of a circle? Its center?
What's the origin of a triangle? Things which shapes have in common are
mostly representation attributes, like colors, border line style an
thickness, or in short, the ability to be drawn in some way and form.
 
J

John C. Bollinger

Anton said:
From the arguments in the previous posts, it is best to avoid casts and
instanceof statements as much as possible.
But sometimes it can have its use.

One situation is the use of so-called 'Marker Interfaces'. An example is
java.io.Serializable.
Such an interface does not declare any methods. Instead it declares a
contract between objects implementing the marker-interface and the users of
such objects and this type of contract can not be expressed with
declarations, using java syntax.

As an example: how would one express the contract of java.io.Serializable
in plain java-code? (the contract stating - in short - that objects
implementing java.io.Serializable must have members that are either
serializable as well or that are volatile)

The user of objects implementing marker-interfaces make use of the
instanceof statement.

What do you all think about using these marker-interfaces?

I do not much care for marker interfaces in general. Most uses of such
interfaces fall right along the lines of the preceding discussion.
Markers can occasionally be useful without reliance on instanceof,
however. Consider Serializable for example, and ignore Generics: if I
want to ensure that a Serializable class really can be serialized
successfully, then I cannot give it non-static, non-transient,
non-Serializable member variables, including variables of type Object.
In this case, the most general type with which I can safely declare
variables is Serializable. Similarly, if I write a general-purpose
method that accepts a reference and attempts to serialize the
corresponding object, then the most general type I can safely assign to
the parameter in question is Serializable.

My opinion in general is that use of a class or interface that is based
on declaring it as the *type* of a reference is pure, good, and
enlightened (at the very abstract level of this discussion) whereas use
of a class or interface involving testing it against the *class* of a
reference is a dabbling with the dark side.
 
B

Betty

Antti S. Brax said:
This is not a new subject. Search Google.

One of the obvious reasons is that every time you use
instanceof you are hardcoding a class name.

I use instance of and don't hardcode a class name!
 
D

Dale King

Thomas said:
It is not equivalent, but good enough for the sake of the discussion.

Except that the poster gave a scenario where instanceof was used and you
gave him a solution for a completely different problem. Not only is it
not equivalent, it was irrelevant.

One pattern that addresses what he was saying where you are given the
superclass reference and must do something different based on the actual
subclass is the visitor pattern.
 
D

Dale King

John said:
I do not much care for marker interfaces in general. Most uses of such
interfaces fall right along the lines of the preceding discussion.
Markers can occasionally be useful without reliance on instanceof,
however. Consider Serializable for example, and ignore Generics: if I
want to ensure that a Serializable class really can be serialized
successfully, then I cannot give it non-static, non-transient,
non-Serializable member variables, including variables of type Object.
In this case, the most general type with which I can safely declare
variables is Serializable. Similarly, if I write a general-purpose
method that accepts a reference and attempts to serialize the
corresponding object, then the most general type I can safely assign to
the parameter in question is Serializable.

My opinion in general is that use of a class or interface that is based
on declaring it as the *type* of a reference is pure, good, and
enlightened (at the very abstract level of this discussion) whereas use
of a class or interface involving testing it against the *class* of a
reference is a dabbling with the dark side.

I'm not sure that Sun agrees with you here. The marker interface concept
is now basically supplanted by annotations. Checking of runtime
annotations is conceptually little different than using instanceof.
 
J

John C. Bollinger

Dale said:
John C. Bollinger wrote:


I'm not sure that Sun agrees with you here. The marker interface concept
is now basically supplanted by annotations. Checking of runtime
annotations is conceptually little different than using instanceof.

Sun may indeed not agree with me here, but I don't find that persuasive
in itself. There does seem to be quite a lot to annotations that
doesn't involve RTTI (-like) behavior, so I'm not prepared to throw out
the whole thing. I haven't really studied the annotation system well
enough to form firm opinions of it, however.
 
H

HalcyonWild

Hi,
Thanks to everyone for posting. Helped me clear my concepts a lot.

Thomas said:
You are using a made-up scenario. Sure, you can't know if you get a
circle or square back from some completely alien method which just
returns shape. However, the point is to try really hard to avoid exactly
this situation. It is not always possible - we have discussed that
already - but you should try.

It is a made up scenario but very similar to an actual situation I had
come across in production code of a system running in one of the
world's largest insurance companies.
We have three info objects, Policy, PolicyA and PolicyB. Both PolicyA
and PolicyB are subclasses of Policy. When the user enters a policy
number on the screen, a method is called which retrieves data from DB
and returns a Policy object. Now there is no way of knowing what is
going to be returned, PolicyA or PolicyB.

So we have code like

public doSomethingWithPolicy(String pNumber)
{
Policy p = policyBean.getPolicyFromDB(pNumber);
//some code
if (p instanceof PolicyA)
{
//do this
}
else (p instanceof PolicyB)
{
//do that
}
//more code
}

The abstract methods in Policy can be used directly.
I understand that if I have to carry out some operations specific to
PolicyA, on PolicyA, like set the contract end date (ie call PolicyA
specific methods), I would have to use configuration class and call it
through the PolicyA or PolicyB (like the ShapeConfig example).
 
H

hawat.thufir

Thomas Weidenfeller wrote:
....
Things which shapes have in common are
mostly representation attributes, like colors, border line style an
thickness, or in short, the ability to be drawn in some way and form.
....

in high school geometry they told me lines don't have a thickness ;)

-Thufir
 

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

No members online now.

Forum statistics

Threads
473,781
Messages
2,569,615
Members
45,296
Latest member
HeikeHolli

Latest Threads

Top