valid use of instanceof or a better way?

Discussion in 'Java' started by VisionSet, Nov 17, 2003.

  1. VisionSet

    VisionSet Guest

    Usually we prefer to avoid instanceof and just call objects by their
    interface type for example and use the fact that the various classes will
    have implemented the method appropriately.

    I have 10 subclasses directly extending Super and all implement a method
    doSomething()

    eg

    class SubA extends Super {

    void doSomething(Super arg) {

    if(arg instanceof SubA) //do something
    if(arg instanceof SubB) //do something
    if(arg instanceof SubC) //do something
    }
    }

    Each subclass has something similar, but the something that they do can not
    be done in a generic way because it depends on which subclass instigates it.

    I don't think I can do this in any other way than instanceof or
    Class.isInstance()

    Or... am I having a stupid day again?

    --
    Mike W
     
    VisionSet, Nov 17, 2003
    #1
    1. Advertising

  2. VisionSet

    Eric Sosman Guest

    VisionSet wrote:
    >
    > Usually we prefer to avoid instanceof and just call objects by their
    > interface type for example and use the fact that the various classes will
    > have implemented the method appropriately.
    >
    > I have 10 subclasses directly extending Super and all implement a method
    > doSomething()
    >
    > eg
    >
    > class SubA extends Super {
    >
    > void doSomething(Super arg) {
    >
    > if(arg instanceof SubA) //do something
    > if(arg instanceof SubB) //do something
    > if(arg instanceof SubC) //do something
    > }
    > }
    >
    > Each subclass has something similar, but the something that they do can not
    > be done in a generic way because it depends on which subclass instigates it.
    >
    > I don't think I can do this in any other way than instanceof or
    > Class.isInstance()


    Ordinarily one would implement a doSomething() method in
    each class, and put the class-specific operations there. Then
    you could just write `arg.doSomething()' and let Java figure
    out which actual method to run.

    This requires that Super also have a doSomething() method.
    You could plant some shared code there, or declare the method
    (and hence Super itself) `abstract', or whatever makes sense.

    If there's something about your situation that discourages
    the use of this "plain vanilla" approach, I'm failing to see
    it. Perhaps a less generic explanation is needed ...

    --
     
    Eric Sosman, Nov 17, 2003
    #2
    1. Advertising

  3. VisionSet

    VisionSet Guest

    "Eric Sosman" <> wrote in message
    news:...
    > VisionSet wrote:
    > >
    > > Usually we prefer to avoid instanceof and just call objects by their
    > > interface type for example and use the fact that the various classes

    will
    > > have implemented the method appropriately.
    > >
    > > I have 10 subclasses directly extending Super and all implement a method
    > > doSomething()
    > >
    > > eg
    > >
    > > class SubA extends Super {
    > >
    > > void doSomething(Super arg) {
    > >
    > > if(arg instanceof SubA) //do something
    > > if(arg instanceof SubB) //do something
    > > if(arg instanceof SubC) //do something
    > > }
    > > }
    > >
    > > Each subclass has something similar, but the something that they do can

    not
    > > be done in a generic way because it depends on which subclass instigates

    it.
    > >
    > > I don't think I can do this in any other way than instanceof or
    > > Class.isInstance()

    >
    > Ordinarily one would implement a doSomething() method in
    > each class, and put the class-specific operations there. Then
    > you could just write `arg.doSomething()' and let Java figure
    > out which actual method to run.
    >
    > This requires that Super also have a doSomething() method.
    > You could plant some shared code there, or declare the method
    > (and hence Super itself) `abstract', or whatever makes sense.
    >
    > If there's something about your situation that discourages
    > the use of this "plain vanilla" approach, I'm failing to see
    > it.


    The point I'm trying to make is that what doSomething() does, does not
    depend just on the subclass it is part of, it also depends on the argument
    to its method which is itself an instance of *one* of these subclasses, it
    is the declared type of this argument that affects the behaviour of the
    doSomething() method.

    > Perhaps a less generic explanation is needed ...



    class Mouse extends Animal {

    void carry(Animal animal) {
    if(animal instanceof Mouse) // carry protesting
    if(animal instanceof Fish) // fish slides off
    if(animal instanceof Dog) // flat mouse
    }

    class Fish extends Animal {

    void carry(Animal animal) {
    if(animal instanceof Mouse) // mouse drowns
    if(animal instanceof Fish) // fish slides off
    if(animal instanceof Dog) // dog decides to swim for it
    }

    class Dog extends Animal {

    void carry(Animal animal) {
    if(animal instanceof Mouse) // dog unaware
    if(animal instanceof Fish) // fish becomes matted in long hair
    if(animal instanceof Dog) // dogs fight
    }

    --
    Mike W
     
    VisionSet, Nov 17, 2003
    #3
  4. VisionSet wrote:

    > Usually we prefer to avoid instanceof and just call objects by their
    > interface type for example and use the fact that the various classes will
    > have implemented the method appropriately.
    >
    > I have 10 subclasses directly extending Super and all implement a method
    > doSomething()
    >
    > eg
    >
    > class SubA extends Super {
    >
    > void doSomething(Super arg) {
    >
    > if(arg instanceof SubA) //do something
    > if(arg instanceof SubB) //do something
    > if(arg instanceof SubC) //do something
    > }
    > }
    >
    > Each subclass has something similar, but the something that they do can not
    > be done in a generic way because it depends on which subclass instigates it.
    >
    > I don't think I can do this in any other way than instanceof or
    > Class.isInstance()
    >
    > Or... am I having a stupid day again?


    I think you're having a bad design day. Either Super represents too
    generic an abstraction, or the subclasses represent too specific
    abstractions, or there is a better way. I would need more details to
    decide which.

    Consider what it is that Super represents, and what it means for a Super
    to doSomething to another Super. It may be that you need to define one
    or more additional methods on Super that subclasses can override to fill
    in the details that instances other subclasses need in order to
    doSomething. (That would constitute an implementation of the Template
    Method pattern, for those keeping score at home. :) )


    John Bollinger
     
    John C. Bollinger, Nov 17, 2003
    #4
  5. VisionSet

    Eric Sosman Guest

    VisionSet wrote:
    >
    > "Eric Sosman" <> wrote in message
    > news:...
    > > VisionSet wrote:
    > > >
    > > > Usually we prefer to avoid instanceof and just call objects by their
    > > > interface type for example and use the fact that the various classes

    > will
    > > > have implemented the method appropriately.
    > > >
    > > > I have 10 subclasses directly extending Super and all implement a method
    > > > doSomething()
    > > >
    > > > eg
    > > >
    > > > class SubA extends Super {
    > > >
    > > > void doSomething(Super arg) {
    > > >
    > > > if(arg instanceof SubA) //do something
    > > > if(arg instanceof SubB) //do something
    > > > if(arg instanceof SubC) //do something
    > > > }
    > > > }
    > > >
    > > > Each subclass has something similar, but the something that they do can

    > not
    > > > be done in a generic way because it depends on which subclass instigates

    > it.
    > > >
    > > > I don't think I can do this in any other way than instanceof or
    > > > Class.isInstance()

    > >
    > > Ordinarily one would implement a doSomething() method in
    > > each class, and put the class-specific operations there. Then
    > > you could just write `arg.doSomething()' and let Java figure
    > > out which actual method to run.
    > >
    > > This requires that Super also have a doSomething() method.
    > > You could plant some shared code there, or declare the method
    > > (and hence Super itself) `abstract', or whatever makes sense.
    > >
    > > If there's something about your situation that discourages
    > > the use of this "plain vanilla" approach, I'm failing to see
    > > it.

    >
    > The point I'm trying to make is that what doSomething() does, does not
    > depend just on the subclass it is part of, it also depends on the argument
    > to its method which is itself an instance of *one* of these subclasses, it
    > is the declared type of this argument that affects the behaviour of the
    > doSomething() method.
    >
    > > Perhaps a less generic explanation is needed ...

    >
    > class Mouse extends Animal {
    >
    > void carry(Animal animal) {
    > if(animal instanceof Mouse) // carry protesting
    > if(animal instanceof Fish) // fish slides off
    > if(animal instanceof Dog) // flat mouse
    > }
    >
    > class Fish extends Animal {
    >
    > void carry(Animal animal) {
    > if(animal instanceof Mouse) // mouse drowns
    > if(animal instanceof Fish) // fish slides off
    > if(animal instanceof Dog) // dog decides to swim for it
    > }
    >
    > class Dog extends Animal {
    >
    > void carry(Animal animal) {
    > if(animal instanceof Mouse) // dog unaware
    > if(animal instanceof Fish) // fish becomes matted in long hair
    > if(animal instanceof Dog) // dogs fight
    > }


    Thanks for the illustration; I now think I see where you're
    heading. However, "where you're heading" is probably "a nice
    place to visit, but you wouldn't want to live there."

    ... that is to say, you could use `instanceof' to implement
    this scheme, but you may come to regret it. When you decide to
    add a Bird class, you'll not only need to write four behaviors
    for Bird itself, but you'll also need to revisit the existing
    Mouse, Fish, and Dog classes and teach them about Bird. And
    then along come Snake and Cat and Armadillo -- you've got an
    N-by-N matrix of behaviors, and the components of the matrix
    are scattered across N different classes, all mutually aware.
    This is the kind of maintenance headache that object-oriented
    design (more specifically, encapsulation) is supposed to cure.

    Can you redesign the model to give that N-by-N behavior
    matrix a "life of its own," as it were? That is, could the
    various behaviors be objects in their own right, managed in
    one class (or one tree of classes) instead of strewn all over
    the landscape?

    --
     
    Eric Sosman, Nov 17, 2003
    #5
  6. VisionSet

    Harald Hein Guest

    "VisionSet" wrote:

    > The point I'm trying to make is that what doSomething() does, does
    > not depend just on the subclass it is part of, it also depends on
    > the argument to its method which is itself an instance of *one* of
    > these subclasses, it is the declared type of this argument that
    > affects the behaviour of the doSomething() method.


    Use method overloading, do what is called a double-dispatch, and/or if
    you have more than one special thing to do, consider the visitor design
    pattern.
     
    Harald Hein, Nov 17, 2003
    #6
  7. VisionSet

    VisionSet Guest

    "John C. Bollinger" <> wrote in message
    news:bpbcs5$1hd$...

    > >
    > > Or... am I having a stupid day again?

    >
    > I think you're having a bad design day.


    Correct!

    > Either Super represents too
    > generic an abstraction, or the subclasses represent too specific
    > abstractions, or there is a better way. I would need more details to
    > decide which.
    >
    > Consider what it is that Super represents, and what it means for a Super
    > to doSomething to another Super. It may be that you need to define one
    > or more additional methods on Super that subclasses can override to fill
    > in the details that instances other subclasses need in order to
    > doSomething. (That would constitute an implementation of the Template
    > Method pattern, for those keeping score at home. :) )
    >


    Yes of course that makes sense, annoying I didn't spot that since it was the
    1st pattern I learnt to use, and before I even realised it was one.

    Thanks

    --
    Mike W
     
    VisionSet, Nov 17, 2003
    #7
  8. > The point I'm trying to make is that what doSomething() does, does not
    > depend just on the subclass it is part of, it also depends on the
    > argument
    > to its method which is itself an instance of *one* of these subclasses,
    > it
    > is the declared type of this argument that affects the behaviour of the
    > doSomething() method.
    >
    >> Perhaps a less generic explanation is needed ...

    >
    >
    > class Mouse extends Animal {
    >
    > void carry(Animal animal) {
    > if(animal instanceof Mouse) // carry protesting
    > if(animal instanceof Fish) // fish slides off
    > if(animal instanceof Dog) // flat mouse
    > }
    >
    > class Fish extends Animal {
    >
    > void carry(Animal animal) {
    > if(animal instanceof Mouse) // mouse drowns
    > if(animal instanceof Fish) // fish slides off
    > if(animal instanceof Dog) // dog decides to swim for it
    > }
    >
    > class Dog extends Animal {
    >
    > void carry(Animal animal) {
    > if(animal instanceof Mouse) // dog unaware
    > if(animal instanceof Fish) // fish becomes matted in long hair
    > if(animal instanceof Dog) // dogs fight
    > }


    You can use a construct like the following. I think it's called "double
    dispatch". It still requires knowledge about the existing subclasses but
    you're gonna have that anyway with interactions like this, and it doesn't
    require use of instanceof.
    abstract class Animal {
    void carry(Animal animal) {
    animal.beCarried(this);
    }
    abstract void carryMouse(Mouse mouse);
    abstract void carryDog(Dog dog);
    abstract void carryFish(Fish fish);
    }
    class Mouse extends Animal {
    void carryMouse(Mouse mouse) {
    protest();
    }
    void carryFish(Fish fish) {
    fish.slideOff();
    }

    void carryDog(Dog dog) {
    splat();
    }
    void beCarried(Animal animal) {
    animal.carryMouse(this);
    }
    }
    class Fish extends Animal {
    void carryMouse(Mouse mouse) {
    mouse.drown();
    }
    void carryFish(Fish fish) {
    fish.slideOff();
    }

    void carryDog(Dog dog) {
    dog.swim();
    }
    void beCarried(Animal animal) {
    animal.carryFish(this);
    }
    }
    ...
    This has the downside that you basically need to enumerate all the
    subclasses in the base class.
    Michiel
     
    Michiel Konstapel, Nov 17, 2003
    #8
  9. VisionSet

    VisionSet Guest

    Plenty to think about, thanks all.
    I'm sure I'll do the right thing when I know more about what I'm dealing
    with.

    --
    Mike W
     
    VisionSet, Nov 17, 2003
    #9
  10. VisionSet

    VisionSet Guest

    "Michiel Konstapel" <> wrote in message
    news:eek:...

    >
    > You can use a construct like the following. I think it's called "double
    > dispatch". It still requires knowledge about the existing subclasses but
    > you're gonna have that anyway with interactions like this, and it doesn't
    > require use of instanceof.
    > abstract class Animal {
    > void carry(Animal animal) {
    > animal.beCarried(this);
    > }
    > abstract void carryMouse(Mouse mouse);
    > abstract void carryDog(Dog dog);
    > abstract void carryFish(Fish fish);
    > }
    > class Mouse extends Animal {
    > void carryMouse(Mouse mouse) {
    > protest();
    > }
    > void carryFish(Fish fish) {
    > fish.slideOff();
    > }
    >
    > void carryDog(Dog dog) {
    > splat();
    > }
    > void beCarried(Animal animal) {
    > animal.carryMouse(this);
    > }
    > }
    > ...
    > This has the downside that you basically need to enumerate all the
    > subclasses in the base class.


    Not quite sure of the advantages of this over instanceof.
    If I add another subclass, I still need to alter all the classes.

    I think perhaps the only ways to avoid this is either model the actual
    behaviours as Eric has suggested, or have a more elaborate inheritence
    hierachy that factors out behaviours up the heierachy. Maybe this is one
    and the same thing or could involve implementing a behaviour interface from
    an interface hierachy.

    --
    Mike W
     
    VisionSet, Nov 17, 2003
    #10
  11. VisionSet

    ak Guest

    don't use instanceof at all!

    > class Mouse extends Animal {
    >
    > void carry(Animal animal) {
    > if(animal instanceof Mouse) // carry protesting
    > if(animal instanceof Fish) // fish slides off
    > if(animal instanceof Dog) // flat mouse
    > }


    class Mouse extends Animal {
    void carry(Mouse mouse) {
    // carry protesting
    }

    void carry(Fish fish) {
    // fish slides off
    }

    void carry(Dog dog) {
    // flat mouse
    }
    }
     
    ak, Nov 17, 2003
    #11
  12. VisionSet wrote:

    >
    > "John C. Bollinger" <> wrote in message
    > news:bpbcs5$1hd$...
    >
    >> >
    >> > Or... am I having a stupid day again?

    >>
    >> I think you're having a bad design day.

    >
    > Correct!
    >
    >> Either Super represents too
    >> generic an abstraction, or the subclasses represent too specific
    >> abstractions, or there is a better way. I would need more details to
    >> decide which.
    >>
    >> Consider what it is that Super represents, and what it means for a Super
    >> to doSomething to another Super. It may be that you need to define one
    >> or more additional methods on Super that subclasses can override to fill
    >> in the details that instances other subclasses need in order to
    >> doSomething. (That would constitute an implementation of the Template
    >> Method pattern, for those keeping score at home. :) )
    >>

    >
    > Yes of course that makes sense, annoying I didn't spot that since it was
    > the 1st pattern I learnt to use, and before I even realised it was one.
    >
    > Thanks
    >
    > --
    > Mike W


    An alternative pattern is the Strategy pattern. It is somewhat more flexible
    than the Template method pattern (you don't need the concrete inheritance,
    but since you have this anyway in this case, it may not matter).

    --
    Regards,
    Christophe Vanfleteren
     
    Christophe Vanfleteren, Nov 18, 2003
    #12
  13. VisionSet

    Adam Guest

    > Not quite sure of the advantages of this over instanceof.
    Using instanceof won't prevent from compiling unfinished
    application (where not all behaviours are implemented).
    If you use Visitor pattern it is compiler resposibility to tell
    you what's missing. Huge advantage in your situation,
    with so many subclasses.
    Moreover instanceof is slower than polymorphic call.

    > If I add another subclass, I still need to alter all the classes.

    It may be a drawback... but still, it makes
    perfect sense to me to define interacion between an object
    of class A and any other object - in class A.
    A Cat knows how to handle Mouse or Dog, noone else.

    But if you plan to do some incremental programming,
    like adding new classes in a longer period of time,
    this can be a pain in the ass to change each class each time you
    add something new. Even though the compiler will tell you
    where you should add some behaviour.

    regards,
    Adam
     
    Adam, Nov 18, 2003
    #13
  14. VisionSet

    Dale King Guest

    "ak" <> wrote in message news:bpbknu$v7h$...
    > don't use instanceof at all!
    >
    > > class Mouse extends Animal {
    > >
    > > void carry(Animal animal) {
    > > if(animal instanceof Mouse) // carry protesting
    > > if(animal instanceof Fish) // fish slides off
    > > if(animal instanceof Dog) // flat mouse
    > > }

    >
    > class Mouse extends Animal {
    > void carry(Mouse mouse) {
    > // carry protesting
    > }
    >
    > void carry(Fish fish) {
    > // fish slides off
    > }
    >
    > void carry(Dog dog) {
    > // flat mouse
    > }
    > }



    That doesn't work. For overloaded methods the choice of which method to call
    is based on the compile-time type of the parameter not the run-time type of
    the object that is referenced. So if I have:

    Mouse m = new Mouse();
    Animal fish = new Fish();
    m.carry( fish );

    That will not call carry( Fish ). It will try to call carry( Animal ) (or
    carry with any super class or super interface of Animal). If that is not
    defined it will not even compile. It will work in combination with the
    double dispatch pattern or visitor pattern however.
    --
    Dale King
     
    Dale King, Nov 18, 2003
    #14
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Digital Puer

    when to use instanceof?

    Digital Puer, Sep 4, 2003, in forum: Java
    Replies:
    3
    Views:
    4,107
    Roedy Green
    Sep 5, 2003
  2. Replies:
    21
    Views:
    21,587
  3. PaulSchrum
    Replies:
    4
    Views:
    662
    Thomas Fritsch
    Jan 23, 2007
  4. François Grondin

    Looking for a way to avoid use of instanceOf

    François Grondin, Dec 4, 2008, in forum: Java
    Replies:
    14
    Views:
    697
    François Grondin
    Dec 4, 2008
  5. Replies:
    2
    Views:
    56
    Mark H Harris
    May 13, 2014
Loading...

Share This Page