Is instanceof dirty?

D

DeMarcus

Hi,

I come from the C++ world and there they say "no no" when
you want to switch on type information. Even the inventor
of C++ say so.

What's the common opinion about using the java keyword
instanceof?


// Daniel
 
E

Eric Sosman

DeMarcus said:
Hi,

I come from the C++ world and there they say "no no" when
you want to switch on type information. Even the inventor
of C++ say so.

What's the common opinion about using the java keyword
instanceof?

Use it when you must. For example, in

class Thing {
public boolean equals(Thing other) {
return ...something...;
}

public boolean equals(Object other) {
return other instanceof Thing
&& equals((Thing)other);
}
}

the `instanceof' seems perfectly normal (and vastly
preferable to catching a ClassCastException). On the
other hand, if you find code like

if (ref instanceof Thing)
...
else if (ref instanceof Ding)
...
else if (ref instanceof Cosa)
...
else
throw new ResException(...);

.... it's probably time to re-think the design.
 
C

Chris Smith

DeMarcus said:
I come from the C++ world and there they say "no no" when
you want to switch on type information. Even the inventor
of C++ say so.

What's the common opinion about using the java keyword
instanceof?

Pretty much the same.

Nevertheless, a lot more dynamic code gets written in Java than in C++,
including stuff with on-the-fly classloaders, mobile code, etc. As a
result, the need for instanceof can become apparent. For example, say
you've developed a plugin architecture based on bytecode, but you need
to ensure that the class the user provides actually implements the
correct interface. This is a case where the traditional disadvantages
of runtime type comparisons are moot, and performing the type check at
runtime is a very good idea.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
S

Stefan Schulz

the `instanceof' seems perfectly normal (and vastly
preferable to catching a ClassCastException). On the
other hand, if you find code like

if (ref instanceof Thing)
...
else if (ref instanceof Ding)
...
else if (ref instanceof Cosa)
...
else
throw new ResException(...);

... it's probably time to re-think the design.

I would not be so strict... i would allow code like

if (ref instanceof GoodBoy)
// do quick and efficiant algorithm only applicable for goodboys
else
// do long and complicated algorithm that works in the general case

A good example of this kind of thinking would be the java.util.RandomAccess
interface.
 
S

Stefan Schulz

Hi,

I come from the C++ world and there they say "no no" when
you want to switch on type information. Even the inventor
of C++ say so.

What's the common opinion about using the java keyword
instanceof?

Try not to use it when other information will do, it is easy
to make mistakes. But it is a useful capability when used in
moderation.

Just my .02$
Stefan
 
E

Eric Sosman

Stefan said:
I would not be so strict... i would allow code like

if (ref instanceof GoodBoy)
// do quick and efficiant algorithm only applicable for goodboys
else
// do long and complicated algorithm that works in the general case

A good example of this kind of thinking would be the java.util.RandomAccess
interface.

"Re-think" is not a synonym for "reject." Re-thinking
the design might lead to the conclusion that nothing should
change, despite appearances. Or, as they say in American
football, "Upon further review, the play stands as called."

With that understood, I'll stand by my opinion (which
I don't think is "strict" at all): Code liberally sprinkled
with `instanceof' operators ought to be re-thought -- but
not necessarily re-written.
 
D

Daniel Grieves

I would disagree with this statement under certain circumstances,
specifically if your design contract for a method specifies that an incoming
variable be of a certain type. For example, I'm a big fan of the old JGL
library (I dunno, I just got hooked on it and never switched over to the
new, templatized Java collection classes). If for example I declare a
method that takes a parameter of type Array, and I specify in the contract
for that method that the Array will contain only objects of type String,
then I would not feel bad about casting blindly and catching (or throwing)
the ClassCastException.

Dan
 
A

Andrea Desole

If you are using instanceof you are making a distinction based on the
type of the class you are referring to. Usually you would get a better
result (in the sense of better code) if you found a way to use
polymorphism, which is usually possible. In this way you make a
distinction based not on the type, but on the logic that the class shows.
Also, in the case of C++, I remember that turning on RTTI implies a
performance penalty. Apparently this is not the same in Java, according
to this article

http://www.javaworld.com/javaworld/jw-02-1998/jw-02-jperf_p.html
 
C

Chris Uppal

DeMarcus said:
What's the common opinion about using the java keyword
instanceof?

I don't disagree with the previous replies that I've seen, but I wanted to give
a slightly different spin to the answer.

Think of it this way: the system (Java's semantics and OO in general) is
designed so that objects are responsible for their own behaviour. That's to
say that it's /their/ responsibility to know "what they are" and what they
should do in any specific circumstance. If you use instanceof then you are
cutting them out of the loop. In effect you are saying, "no, I don't care what
you think, I'm going to do this /my/ way".

Now that's fine if you know what you are doing and have a good reason. But you
are also throwing away the modularity, flexibility, comprehensibility, and
maintainability that were the point of using OO in the first place.

You can think of 'instanceof' as a specific kind of reflection. Other examples
of reflection are the facilities in java.lang.reflect for looking at what
methods and fields are available, and the use of finalize() to reflect on an
object's lifetime. These features allow you more power and control over the
way the system works, but at the cost that /you/ have taken over responsibility
for some aspect of the operation that the system would otherwise look after for
you. Reflection in general is something that "ordinary" programs don't, and
shouldn't, make much use of. (Although, as Chris Smith noted, it does depend
on how dynamic a programming environment / language you are working with[*])
In general, even if you do need to use reflection (and 'instanceof'
specifically) to make some design work, then it won't be as ad-hoc hacks
scattered randomly around the system. You'd be able to look at the design in
advance and say (after some thought) "we'll need to use reflection <here> and
<here>, there's no need for it anywhere else".

And I think that's the point: if you are just scattering 'instanceof' around in
an arbitrary way (if a reader can't look at what a method does and reliably
guess whether you'd use 'instanceof' before reading your code) then you are
almost certainly creating an ugly mess of hacks.

BTW, there's nothing /inherently/ wrong with slimy hacks. Sometimes you can
use a well-placed hack to gather all the ugliness of (part of) a system into
one place and hide it where it doesn't affect everything else. You'll be able
to recognise such uses quite easily since there will be a long comment
apologising for the hack, and explaining why it's better than the alternatives
in this case.

([*] E.g. I don't think I've ever used RTTI in C++ (a desperately static
environment), I can't have used 'instanceof' more than twice in Java (also
desperately static), yet I must have used it about 100 times in Smalltalk where
I can program in a /much/ more dynamic style.)

-- chris
 
X

xarax

Chris Uppal said:
DeMarcus said:
What's the common opinion about using the java keyword
instanceof?

I don't disagree with the previous replies that I've seen, but I wanted to give
a slightly different spin to the answer.

Think of it this way: the system (Java's semantics and OO in general) is
designed so that objects are responsible for their own behaviour. That's to
say that it's /their/ responsibility to know "what they are" and what they
should do in any specific circumstance. If you use instanceof then you are
cutting them out of the loop. In effect you are saying, "no, I don't care what
you think, I'm going to do this /my/ way".

Now that's fine if you know what you are doing and have a good reason. But you
are also throwing away the modularity, flexibility, comprehensibility, and
maintainability that were the point of using OO in the first place.

You can think of 'instanceof' as a specific kind of reflection. Other examples
of reflection are the facilities in java.lang.reflect for looking at what
methods and fields are available, and the use of finalize() to reflect on an
object's lifetime. These features allow you more power and control over the
way the system works, but at the cost that /you/ have taken over responsibility
for some aspect of the operation that the system would otherwise look after for
you. Reflection in general is something that "ordinary" programs don't, and
shouldn't, make much use of. (Although, as Chris Smith noted, it does depend
on how dynamic a programming environment / language you are working with[*])
In general, even if you do need to use reflection (and 'instanceof'
specifically) to make some design work, then it won't be as ad-hoc hacks
scattered randomly around the system. You'd be able to look at the design in
advance and say (after some thought) "we'll need to use reflection <here> and
<here>, there's no need for it anywhere else".

And I think that's the point: if you are just scattering 'instanceof' around in
an arbitrary way (if a reader can't look at what a method does and reliably
guess whether you'd use 'instanceof' before reading your code) then you are
almost certainly creating an ugly mess of hacks.

BTW, there's nothing /inherently/ wrong with slimy hacks. Sometimes you can
use a well-placed hack to gather all the ugliness of (part of) a system into
one place and hide it where it doesn't affect everything else. You'll be able
to recognise such uses quite easily since there will be a long comment
apologising for the hack, and explaining why it's better than the alternatives
in this case.
/snip/

I agree. Using "instanceof" is similar to using a switch block
with some kind of "type code" thing that distinguishes the actual
type. The general rule of OOP is that such constructs should be
replaced with polymorphism where possible. In the case of external
non-OO data, a switch block is necessary for creating the initial
object with an appropriate subtype.

I've used "instanceof" mostly in places where I was too lazy
to do it the right way. For example, an ArrayList that has both
JPanel and JLabel instances, I would use "instanceof" to distinguish
and downcast the next instance that I pulled from the ArrayList. It
was simple, it worked, and the ArrayList was very private. There was
no way that the "instanceof" usage could spread through-out the
application.


For a more flexible approach, I use something like this:
=========================================
public class Fubar
{
public void doGork(final Gork gork)
{
/* I want to do something with a Gork
that depends on the actual subtype
of Gork. */
gork.invoke(this);
}

public void doSomething(final Snafu snafu)
{
/* Snafu is a subtype of Gork. */
}


public void doSomething(final Gecko gecko)
{
/* Gecko is a subtype of Gork. */
}
}

public abstract class Gork
{
public abstract void invoke(Fubar fubar);
}

public class Snafu
extends Gork
{
public void invoke(final Fubar fubar)
{
/* calls Fubar.doSomething(Snafu) */
fubar.doSomething(this);
}
}


public class Gecko
extends Gork
{
public void invoke(final Fubar fubar)
{
/* calls Fubar.doSomething(Gecko) */
fubar.doSomething(this);
}
}
=========================================

This is a form of reflection that uses
overloading to distinguish the actual
subtype of Gork that was passed to
Fubar.doGork(Gork).

Since Fubar must know all of the subtypes of
Gorko (which it must know anyway when using
instanceof), this technique avoids instanceof
and achieves the same effect of distinguishing
the actual subtype of Gork on behalf of
Fubar.doGork(Gork).

A little imagination can extend this technique
to many subtypes of Gork by just adding the
appropriate overloaded "doSomething" method to
Fubar, and defining the new subtype of Gork with
the "invoke(Fubar)" method.

Notice that even though the "invoke" methods in
each of the subclasses are textually the same, their
effect is very different from each due to the usage
of "this" in the method call, which distinguishes
which overloaded "doSomething" method is called. You
would not want to refactor these methods to the parent
abstract class (do you see why?).

This is a very clean usage of polymorphism that
avoids "instanceof" and clearly separates the
work that Fubar.doGork(Gork) wants to perform on
the actual subtype of Gork.


--
----------------------------
Jeffrey D. Smith
Farsight Systems Corporation
24 BURLINGTON DRIVE
LONGMONT, CO 80501-6906
http://www.farsight-systems.com
z/Debug debugs your Systems/C programs running on IBM z/OS for FREE!
 
J

Jesper Nordenberg

DeMarcus said:
Hi,

I come from the C++ world and there they say "no no" when
you want to switch on type information. Even the inventor
of C++ say so.

What's the common opinion about using the java keyword
instanceof?

While I basicly agree with the other posts I think there are cases
when instanceof is unavoidable. One good example is you want traverse
a tree and want to perform different operations depending on the type
of node you encounter. One might argue that the visitor pattern should
be used in this case, but that requires that support for the visitor
pattern has been implemented in the node class structure. You can't
extend an existing class structure with the visitor pattern. Even if
the visitor pattern has been implemented it's very awkward and
inflexible solution that don't allow arbitrary arguments to be passed.
The cleanest solution, which unfortunately is impossible to implement
in Java, is multi-methods like those found in Nice,
http://nice.sourceforge.net/visitor.html. In Java your best option is
to use lots of "if (node instanceof X)" statements. Or you can use a
Map<Class, Runnable> solution. Both are solutions are sub-optimal.

/Jesper Nordenberg
 
J

John C. Bollinger

Chris said:
Think of it this way: the system (Java's semantics and OO in general) is
designed so that objects are responsible for their own behaviour. That's to
say that it's /their/ responsibility to know "what they are" and what they
should do in any specific circumstance. If you use instanceof then you are
cutting them out of the loop. In effect you are saying, "no, I don't care what
you think, I'm going to do this /my/ way".

Now that's fine if you know what you are doing and have a good reason. But you
are also throwing away the modularity, flexibility, comprehensibility, and
maintainability that were the point of using OO in the first place.

The one place where I find myself frequently using instanceof in Java is
in equals() methods, where it is common that I want to determine whether
the object to compare to is an instance of the class to which the method
belongs (so as to perform a comparison appropriate for that class, or
return false if that's not possible). That particular kind of use
doesn't seem to quite to square with your characterization (above)
because the question isn't really a generic "what class are you?" but
rather "is your class compatible with mine?". Would you agree that that
kind of use makes more sense in your worldview? Do you have a preferred
idiom to suggest?


John Bollinger
(e-mail address removed)
 
G

George Neuner

Hi,

I come from the C++ world and there they say "no no" when
you want to switch on type information.

Where did you get that idea? Many dynamic object creation problems
can require code to deliberately switch on object types.
Even the inventor of C++ say so.

Stroustrap has never said "don't do it" - rather he has repeatedly
said that RTTI is a powerful mechanism that should be used
responsibly. C++ code that explicitly uses run time type information
is generally not portable and requires above average attention to
detail.

RTTI query support was left implementation specific in the first
versions of the C++ language standard (I don't have the latest version
available to check if it is still the case). Stroustrap's early books
on C++ include examples using the standard cast operators to construct
an ad-hoc type query mechanism for cases where native compiler RTTI
query support was not available.

What's the common opinion about using the java keyword
instanceof?

The functionality would not have been provided if Java's designers
didn't think it was needed. In contrast to the C++ crowd, they were
nice enough to provide a standard way to query RTTI from the start.

Using "instanceof" in Java is a perfectly acceptible way to write code
that must manipulate versioned interfaces (just as the equivalent code
would be in C++). Others have mentioned alternate good uses for it as
well.


George
 
C

Chris Uppal

John said:
The one place where I find myself frequently using instanceof in Java is
in equals() methods, [...]
That particular kind of use
doesn't seem to quite to square with your characterization (above)
because the question isn't really a generic "what class are you?" but
rather "is your class compatible with mine?". Would you agree that that
kind of use makes more sense in your worldview?

Yes, I'd forgotten about that case. Thanks for the reminder. It does indeed
make more sense.

But equals() is such a very odd method. That's to say, the concept of
"equality" as used in programming is so very odd -- I don't think there's
anything specifically odd about the Java equals() method.

It /looks/ innocous enough, but it's really very strange.

For one thing it applies between all pairs of objects, no matter how unrelated
they are (which, basically, is why you need the instanceof test, or an
equivalent). Normally it would be seen as a congitive error (category error)
to try to compare, say, an IncomeTaxBand with an IncomeTaxReturn, let alone
with an AbstractRenderable, but equals() is expected to be up to the task...

And then too, it's context independent, but for real purposes comparison
/isn't/ independent of the context. You are normally wanting to know if two
things are "the same" /for some purpose/, yet there's no mention of the context
in equals().

There's something twisted about the object-modelling involved in equals(). I'm
almost tempted to say that it shouldn't exist at all. It's certainly very
ungainly.

Do you have a preferred idiom to suggest?

Not really.

Actually, I /think/[*] I prefer to express the class-test in equals() as:

this.getClass() == anObject.getClass()

rather than hardwiring a reference to "my" class into the code (and that also
avoids the potential problem, or at least ambiguity, with subclasses). But it
comes down to pretty-much the same thing.

([*] I can't remember ever implementing equals() in Java, which may be
significant in itself -- or maybe I'm just in denial ;-)

There's an idiom (widely used in the Smalltalk class hierarchy, for instance)
which is slightly more flexible than the class-test. I'm not sure I like it
myself -- it doesn't really cure the equals() problems, although it does help.
The idiom is that an object has a 'species' which is normally its own class,
but may be some other class (usually a superclass), and the equals() method can
compare species rather than classes:

return this.getSpecies() == anObject.getSpecies()
&& // ... rest of comparison

The idea is that it is testing /type/ not class, and doing so idiomatically by
nominating (slightly arbitrarily) a specific class which is then taken to
exemplify the type shared by a whole category of concrete classes. "Paradigm"
would be a better name than "species", but unfortunately that word has been
hijacked by bloody Kuehn (sp?) and I don't think many people would recognise it
in the correct/original sense of "defining example".

It's not something you could use directly in Java, since that would require
getSpecies() to be defined by java.lang.Object, though you could use instanceof
to emulate it. An elegant variant would be to use an interface as the
nominated (paradigmatic) class. Come to think of it, maybe that's how you
/are/ using instanceof in your applications ?

-- chris
 
S

Stefan Schulz

John said:
The one place where I find myself frequently using instanceof in Java is
in equals() methods,
[...]
Actually, I /think/[*] I prefer to express the class-test in equals() as:

this.getClass() == anObject.getClass()

rather than hardwiring a reference to "my" class into the code (and that
also
avoids the potential problem, or at least ambiguity, with subclasses).
But it
comes down to pretty-much the same thing.

([*] I can't remember ever implementing equals() in Java, which may be
significant in itself -- or maybe I'm just in denial ;-)

This will fail if you get an Object of a subclass of your own... one you
could
compare (and which would be an instanceof your class=
 
C

Chris Uppal

This will fail if you get an Object of a subclass of your own... one you
could
compare (and which would be an instanceof your class=

Well, that's my point isn't it -- or part of my point anyway ? Whether, and
why, an object could be considered to be equal() to an instance of a subclass
of its own class is not well-defined. Maybe it should, maybe it shouldn't.
It's probably context dependent. It's certainly application dependent. But I
think it's worse than that:

Consider two classes Super and Sub, where Sub extends Super. Consider two
objects aSuper and aSub. Now if (as may be reasonable) you want it to be true
that:

aSuper.equals(aSub)

then it should also be true that:

aSub.equals(aSuper)

In which case the 'instanceof' test in Sub.equals() must be allowing instances
of its superclass. (This could be thought of as an application of the 'species'
pattern I mentioned.) In such cases we are essentially saying that not only
can Subs be substituted for Supers (in the sense of the Liskov Substitution
Principle), but also that Supers can be substituted for Supers -- that they are
interchangable (modulo polymorphically differing behaviour). Class hierarchies
that have that property are certainly not ill-formed (I'd argue that they are
exceptionally well-formed), but they are not the general rule. Normally
substitutability only runs in one direction.

So we see another oddness (in OO terms) about equals(). It must either (in the
general case) fail to be symmetric (an abomination) or it must fail to be
compatible with the LSP.

Continuing a thought from my earlier post. Considering the shear oddness of
equals(), and the extaordinary wide contract that it is supposed to fulfill,
it's not surprising that it is forced to employ "unusual" techniques like
reflection.

-- chris
 
J

John C. Bollinger

Chris said:
John C. Bollinger wrote:
But equals() is such a very odd method. That's to say, the concept of
"equality" as used in programming is so very odd -- I don't think there's
anything specifically odd about the Java equals() method.

It /looks/ innocous enough, but it's really very strange.

[...]

Agreed. Unfortunately, there is no getting around it. It is much too
deeply ingrained in the language and class libraries.
Do you have a preferred idiom to suggest?


Not really.

Actually, I /think/[*] I prefer to express the class-test in equals() as:

this.getClass() == anObject.getClass()

rather than hardwiring a reference to "my" class into the code (and that also
avoids the potential problem, or at least ambiguity, with subclasses). But it
comes down to pretty-much the same thing.

I tend to fall on the other side of the question of equality with
instances of subclasses, so instanceof usually expresses my intent
accurately. There is a reflective solution that would mirror instanceof
perfectly, but I really don't see the point of doing that in such a case.
There's an idiom (widely used in the Smalltalk class hierarchy, for instance)
which is slightly more flexible than the class-test. I'm not sure I like it
myself -- it doesn't really cure the equals() problems, although it does help.
The idiom is that an object has a 'species' which is normally its own class,
but may be some other class (usually a superclass), and the equals() method can
compare species rather than classes:

return this.getSpecies() == anObject.getSpecies()
&& // ... rest of comparison

The idea is that it is testing /type/ not class, and doing so idiomatically by
nominating (slightly arbitrarily) a specific class which is then taken to
exemplify the type shared by a whole category of concrete classes.

I like that. It perfectly expresses the answer to the relevant
question, including providing a clean solution for the subclass issue.
It's not something you could use directly in Java, since that would require
getSpecies() to be defined by java.lang.Object, though you could use instanceof
to emulate it.

Which is more or less where we started, I think. At least, substituting
an instanceof test for the equality test in your example results in
the Java idiom that I normally use in these cases.
An elegant variant would be to use an interface as the
nominated (paradigmatic) class. Come to think of it, maybe that's how you
/are/ using instanceof in your applications ?

I wish I could lay claim to such elegance, but sadly, no, my typical
usage is more mundane.

Thanks for the comments.

Cheers,

John Bollinger
(e-mail address removed)
 
A

Andrea Desole

Stefan said:
John said:
The one place where I find myself frequently using instanceof in Java is
in equals() methods,

[...]
Actually, I /think/[*] I prefer to express the class-test in equals() as:

this.getClass() == anObject.getClass()

rather than hardwiring a reference to "my" class into the code (and
that also
avoids the potential problem, or at least ambiguity, with
subclasses). But it
comes down to pretty-much the same thing.

([*] I can't remember ever implementing equals() in Java, which may be
significant in itself -- or maybe I'm just in denial ;-)


This will fail if you get an Object of a subclass of your own... one
you could
compare (and which would be an instanceof your class=

I think Chris is right. The equals method has to be symmetric, according
to the documentation. This means that superclass.equals(subclass) must
return false
 

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,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top