D
dmx_dawg
Hi all.
I just decided to write a message regarding the myth that the use of
the instanceof keyword is categorically bad. Not all java programmers
have fallen prey to the myth, but after years on the newsgroups it has
almost gotten to the point where if it was discovered that you used
instanceof anywhere in your app, it *must* be because you have a poorly
designed system.
Is this a situation of 'bad-practice-phobia', where the fear of being
thought of as a newbie programmer (or worse, a 'hack' who still
'doesn't get' OO) makes people create the most elaborately complex and
unmaintainable designs to avoid using a specific 'bad practice'?
I think what's very often forgotten is that a bad practice can never be
reduced to something as simplistic as 'never ever use keyword X'. All
bad practices have there 'scope of ill-use'--which may be very big--but
are almost never (if ever) absolute.
Specifics:
Alex Blewitt's Javaworld article
================================
It has been said that, in most cases, instanceof should not be used to
test for object equality (see [BLEWITT1]) as it can break the symmetric
property of the equals method's equivalence relation. In this case,
using the getClass method of Object is the appropriate choice. This
makes a lot of sense.
But notice that Mr. Blewitt's article never simply says 'always use
getClass over instanceof'. He explicitly states a specific situation
in which using instanceof is not appropriate. So next time someone
cites Mr. Blewitt's article to prove your use of instanceof is bad
without even seeing your code, you can be fairly certain they've
probably never actually read the article. They are simply deep in the
'instanceof is always, always bad' myth.
Yoe see, getClass will always return the runtime class of an object and
is useless if what you want to determine is whether an object falls
within a specific inheritance hierarchy. In the example below, we want
to determine if an object's class implements a specific interface.
Here getClass does not help us.
class A implements IShared
{
}
A a = new A();
a instanceof A; // true
a instanceof IShared; // true
a.getClass() == A.class // true
a.getClass() == IShared.class // false
Now, of course, this is a contrived example with no context, but the
need to check whether an object can be polymorphically treated as a
specific type--wherever that type may exist in its inheritance
hierarchy--can often be useful in practice (see the references section
for some specific examples of this, such as those uses found in the
Ecplipse framework).
Avoiding instanceof
===================
Another thing you may find on the net are people who will try their
darndest to provide you with an example of how you can get around using
instanceof. They will explain that you need their complex, difficult
to maintain, cyclic-dependency-creating solutions because your design
is bad (you used instanceof right?... so it *must* be bad), and that
your solution will certainly be a nightmare to maintain in the future.
Let's take a brief look at some of the common 'solutions'.
Use method overloading instead
==============================
Some may say that you simply need to overload a number of methods with
different class parameters. Why use instanceof to determine if an
object's class implements a specific interface? Let the overloading
functionality of the language do this for you!
The problem is that
interface Animal
{
public void move();
}
class Fish implements Animal
{
public void move()
{
System.out.println("swim!");
}
public void eatAlgae(){}
}
class Mouse implements Animal
{
public void move()
{
System.out.println("scurry!");
}
public void makeHoleInWall(){}
}
So now we can create methods such as
class Test
{
public void scare(Mouse m)
{
m.move();
m.makeHoleInWall();
}
public void scare(Fish fish)
{
f.move();
f.eatAlgae();
}
public Test()
{
Animal fish = new Fish();
scare(fish); // does not compile
}
}
So what happened? Why doesn't this even compile? Because the fish
object's compile-time type is Animal, *not Fish*. Of course, we could
get around this by creating a new scare(Animal a) method, but then
we're right back where we started.
Visitor (and Proxy Visitor)
===========================
Another option that is often brought up is the use of the Visitor
pattern. The problem with this is that it creates a huge maintenance
issue. Visitor requires updating all of the 'visitable' classes every
time we add new visitable class into the pattern.
Why not use adapter classes then? The problem is that in Java, its not
always simple for 'visitable' classes to extend a 'VistableAdapter' (to
avoid implementing an accept method for every possible visitable class)
due Java's single inheritance (e.g.: if your class is already extending
a class, you're out of luck unless you want to get into some messy
code). This turns the Visitor pattern into a maintenance nightmare.
Now I have obviously skimmed over this one very quickly, but this is
because Robert C. Martin has already ready written on this better than
I could. Check out his web page on the subject [MARTIN1], as well (if
you have ACM Portal access) his published paper on it [MARTIN2].
Other people using instanceof
=============================
I encourage people to check out some of the other sources I've listed
here. Maybe if people found out that the Eclipse framework uses
instanceof [OTAKU], or if after they read an article by Bill Venners
with a section explicitly titles 'When to use instanceof' [VENNERS],
they will see that one should always beware of grand sweeping
generalizations in any situation. So go ahead and use instanceof when
it's appropriate, avoid it when it's not appropriate, and don't believe
the hype!
Cheers!
Michael N. Christoff
References
==========
BLEWITT
Object equality--Writing equals and hashCode methods for data objects
http://www.javaworld.com/javaworld/jw-06-2004/jw-0614-equals.html
MARTIN1
Visitor vs instanceof
http://butunclebob.com/ArticleS.UncleBob.VisitorVersusInstanceOf
MARTIN2
Acyclic visitor
http://portal.acm.org/citation.cfm?id=273456&dl=ACM&coll=portal
VENNERS
See section "When to use instanceof" at the following link:
http://www.artima.com/objectsandjava/webuscript/PolymorphismInterfaces1.html
OTAKU
See section "Extensibility the interface way"
http://www.beust.com/weblog/archives/2005_06.html
I just decided to write a message regarding the myth that the use of
the instanceof keyword is categorically bad. Not all java programmers
have fallen prey to the myth, but after years on the newsgroups it has
almost gotten to the point where if it was discovered that you used
instanceof anywhere in your app, it *must* be because you have a poorly
designed system.
Is this a situation of 'bad-practice-phobia', where the fear of being
thought of as a newbie programmer (or worse, a 'hack' who still
'doesn't get' OO) makes people create the most elaborately complex and
unmaintainable designs to avoid using a specific 'bad practice'?
I think what's very often forgotten is that a bad practice can never be
reduced to something as simplistic as 'never ever use keyword X'. All
bad practices have there 'scope of ill-use'--which may be very big--but
are almost never (if ever) absolute.
Specifics:
Alex Blewitt's Javaworld article
================================
It has been said that, in most cases, instanceof should not be used to
test for object equality (see [BLEWITT1]) as it can break the symmetric
property of the equals method's equivalence relation. In this case,
using the getClass method of Object is the appropriate choice. This
makes a lot of sense.
But notice that Mr. Blewitt's article never simply says 'always use
getClass over instanceof'. He explicitly states a specific situation
in which using instanceof is not appropriate. So next time someone
cites Mr. Blewitt's article to prove your use of instanceof is bad
without even seeing your code, you can be fairly certain they've
probably never actually read the article. They are simply deep in the
'instanceof is always, always bad' myth.
Yoe see, getClass will always return the runtime class of an object and
is useless if what you want to determine is whether an object falls
within a specific inheritance hierarchy. In the example below, we want
to determine if an object's class implements a specific interface.
Here getClass does not help us.
class A implements IShared
{
}
A a = new A();
a instanceof A; // true
a instanceof IShared; // true
a.getClass() == A.class // true
a.getClass() == IShared.class // false
Now, of course, this is a contrived example with no context, but the
need to check whether an object can be polymorphically treated as a
specific type--wherever that type may exist in its inheritance
hierarchy--can often be useful in practice (see the references section
for some specific examples of this, such as those uses found in the
Ecplipse framework).
Avoiding instanceof
===================
Another thing you may find on the net are people who will try their
darndest to provide you with an example of how you can get around using
instanceof. They will explain that you need their complex, difficult
to maintain, cyclic-dependency-creating solutions because your design
is bad (you used instanceof right?... so it *must* be bad), and that
your solution will certainly be a nightmare to maintain in the future.
Let's take a brief look at some of the common 'solutions'.
Use method overloading instead
==============================
Some may say that you simply need to overload a number of methods with
different class parameters. Why use instanceof to determine if an
object's class implements a specific interface? Let the overloading
functionality of the language do this for you!
The problem is that
interface Animal
{
public void move();
}
class Fish implements Animal
{
public void move()
{
System.out.println("swim!");
}
public void eatAlgae(){}
}
class Mouse implements Animal
{
public void move()
{
System.out.println("scurry!");
}
public void makeHoleInWall(){}
}
So now we can create methods such as
class Test
{
public void scare(Mouse m)
{
m.move();
m.makeHoleInWall();
}
public void scare(Fish fish)
{
f.move();
f.eatAlgae();
}
public Test()
{
Animal fish = new Fish();
scare(fish); // does not compile
}
}
So what happened? Why doesn't this even compile? Because the fish
object's compile-time type is Animal, *not Fish*. Of course, we could
get around this by creating a new scare(Animal a) method, but then
we're right back where we started.
Visitor (and Proxy Visitor)
===========================
Another option that is often brought up is the use of the Visitor
pattern. The problem with this is that it creates a huge maintenance
issue. Visitor requires updating all of the 'visitable' classes every
time we add new visitable class into the pattern.
Why not use adapter classes then? The problem is that in Java, its not
always simple for 'visitable' classes to extend a 'VistableAdapter' (to
avoid implementing an accept method for every possible visitable class)
due Java's single inheritance (e.g.: if your class is already extending
a class, you're out of luck unless you want to get into some messy
code). This turns the Visitor pattern into a maintenance nightmare.
Now I have obviously skimmed over this one very quickly, but this is
because Robert C. Martin has already ready written on this better than
I could. Check out his web page on the subject [MARTIN1], as well (if
you have ACM Portal access) his published paper on it [MARTIN2].
Other people using instanceof
=============================
I encourage people to check out some of the other sources I've listed
here. Maybe if people found out that the Eclipse framework uses
instanceof [OTAKU], or if after they read an article by Bill Venners
with a section explicitly titles 'When to use instanceof' [VENNERS],
they will see that one should always beware of grand sweeping
generalizations in any situation. So go ahead and use instanceof when
it's appropriate, avoid it when it's not appropriate, and don't believe
the hype!
Cheers!
Michael N. Christoff
References
==========
BLEWITT
Object equality--Writing equals and hashCode methods for data objects
http://www.javaworld.com/javaworld/jw-06-2004/jw-0614-equals.html
MARTIN1
Visitor vs instanceof
http://butunclebob.com/ArticleS.UncleBob.VisitorVersusInstanceOf
MARTIN2
Acyclic visitor
http://portal.acm.org/citation.cfm?id=273456&dl=ACM&coll=portal
VENNERS
See section "When to use instanceof" at the following link:
http://www.artima.com/objectsandjava/webuscript/PolymorphismInterfaces1.html
OTAKU
See section "Extensibility the interface way"
http://www.beust.com/weblog/archives/2005_06.html