Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doubts about the use of polymorphism, and also about how is polymorphism related to casting?

I give lessons on the fundamentals of the Java programming language, to students who study this subject in college.

Today one of them got me really confused with her question, so I told her to give me just a day to think about the problem, and I'll give her as accurate of an answer as I can.

She told me that the teacher got really angry when she used the keyword instanceof in her exam.

Also, she said that the teacher said that there is not a way to prove how polymorphism worked if she used that word.

I thought a lot to try to find a way to prove that in some occasions we need to use instanceof, and also that even if we use it, there still some polymorphism in that approach.

So this is the example I made:

public interface Animal
{
    public void talk();
}

class Dog implements Animal {        
    public void talk() {
        System.out.println("Woof!");
    }
}

public class Cat implements Animal
{
    public void talk() {
         System.out.println("Meow!");
    }    

    public void climbToATree() {
          System.out.println("Hop, the cat just cimbed to the tree");
    }
}

class Hippopotamus implements Animal {
    public void talk() {
        System.out.println("Roar!");
    }    
}

public class Main {
    public static void main(String[] args) {
        //APPROACH 1
        makeItTalk(new Cat());
        makeItTalk(new Dog());
        makeItTalk(new Hippopotamus());

       //APPROACH 2
        makeItClimbToATree(new Cat());
        makeItClimbToATree(new Hippopotamus());
    }

    public static void makeItTalk(Animal animal) {
        animal.talk();
    }

   public static void makeItClimbToATree(Animal animal) {
       if(animal instanceof Cat) {
            ((Cat)animal).climbToATree();                  
       }
       else {
           System.err.println("That animal cannot climb to a tree");
        }
    }
}

My conclusions are the following:

  • The first approach (APPROACH 1) is a simple demo of how to program to an interface, not a realization. I think that the polymorphism is clearly visible, in the parameters of the method makeItTalk(Animal animal), and also in the way the method talk is called, by using the animal object.(This part is ok)

  • The second part is the one that makes me confused. She used instanceof at some point in her exam (I don't know how their exam looked like), and that was not accepted correctly because the teacher said, you are not proving polymorphism.

To help her understand when she can use instanceof, I thought about telling her, that she can use it, when the method she needs to call is not in the interface, but it is just in one of the implementing classes.

As you can see, only cats can climb to trees, and it would not be logical to make a Hippopotamus or a Dog climb to a tree. I think that could be an example of when to use instanceof

  • But what about polymorphism in approach 2?

  • How many uses of polymorphism do you see there (only approach 2)?

  • Do you think this line has some type of polymorphism in it?

    ((Cat)animal).climbToATree();

I think it does, because in order to achieve a Casting of this type, the objects need to have an IS-A relationship, an in some way that is polymorphism.

  • What do you think, is it correct?

  • If yes, how would you explain with your own words, that casting relies on polymorphism?

like image 964
javing Avatar asked Jun 03 '11 23:06

javing


People also ask

What is polymorphism how does it relate to methods?

Polymorphism is the method in an object-oriented programming language that performs different things as per the object's class, which calls it. With Polymorphism, a message is sent to multiple class objects, and every object responds appropriately according to the properties of the class.

What is the main purpose of polymorphism?

Polymorphism allows us to perform a single action in different ways. In other words, polymorphism allows you to define one interface and have multiple implementations. The word “poly” means many and “morphs” means forms, So it means many forms.

What is casting polymorphism?

Inheritance in Object-Oriented Programming creates an IS-A relationship between objects. You can think of these relationships like a family tree — a parent to child— relationship where genes from the parents are passed to their children.

What are two techniques to implement polymorphism?

Polymorphism in Java has two types: Runtime polymorphism (dynamic binding) and Compile time polymorphism (static binding). Method overriding is an example of dynamic polymorphism, while method overloading is an example of static polymorphism.


2 Answers

The reason the instanceof method is seen as bad is simple. Cats aren't the only Animal that might be able to climb a tree.

What happens if down the road you need to add a Koala class. Then your simple if becomes a not so simple or. Then, what happens when you add another class? and another one. And another one. That's the prime reason why instanceof is seen as bad. Because it couples the implementation to a concrete class, rather than opening it for the callee to determine what to do.

Simply implement the makeItClimbToATree() method to throw a CantClimbTreesException if called on an animal that can't climb. That way you have the best of both worlds. Easy to implement, and easy to extend.

IMHO, instanceof has only 1 truly valid use: In a test case to test the returned instance from a method matches the expected return type (in non-type safe languages).

Basically any other use can more than likely be refactored away or designed differently to negate the need for its use.

Another way to look at it is this: Polymorphism allows you to eliminate almost all conditional statements from your code. The only conditionals that you can't get rid of (at least all of them) are in object creational methods (such as in a factory where it must choose the class based upon a runtime argument). Just about any other conditional can be replaced by polymorphism. Therefore, anything that does conditional execution is by definition anti-polymorphic. That's not to say it's bad (there's a huge difference between Good and Good Enough), But in an academic discussion, it's not polymorphic...

Never forget the 60/60 rule. 60% of your total development time will be spent maintaining the code you wrote, and 60% of that time will be spent adding new features. Make maintaining easier, and your life will be easier as well. That's why instanceof is bad. It makes the initial design easier, but complicates the long term maintenance (which is more expensive anyway)...

like image 83
ircmaxell Avatar answered Oct 09 '22 01:10

ircmaxell


In your above example, there is no need to call

makeItClimbToATree (new Hippopotamus ());

It could be easily avoided, if makeItClimbToATree wouldn't expect an animal, but something more specific, which is really able to climb a tree. The necessity to allow animals, and therefore to use instanceof, isn't visible. If you manage the animals in a List of animals, it will be more obvious.

While ircmaxells explanation starts great, while introducing the Koala and other TreeClimbers, he doesn't see a second extension which is hiding in a sea anemone: different capabilities of animals like seaAnemoneHider, winterSleeping, blueEyed, bugEating, and so on, and so on. You would end up with boolean over boolean, constantly recompiling the base class, as well as breaking extending customer classes, which would need recompilation again, and wouldn't be able to introduce their own possibilities in a similar manner.

Customer A would need Customer B to declare a NotBugEatingException, to get your behaviour into the base class.

Introducing your own interfaces, combined with instanceof, is a much cleaner approach, and more flexible. Customer A might define divingLikeAPenguin and customer B trumpeting, both not knowing of each other, both not affecting the Animal class and not provoking useless recompilations.

import java.util.*;

interface Animal {
    public void talk ();
}

interface TreeClimbing {
    public void climbToATree ();
}

class Dog implements Animal {
    public void talk () { System.out.println("Woof!"); }
}

class Cat implements Animal, TreeClimbing {
    public void talk () { System.out.println("Meow!"); }    
    public void climbToATree () { System.out.println ("on top!"); }
}

public class TreeCriterion {

    public static void main(String[] args) {
        List <Animal> animals = new ArrayList <Animal> ();
        animals.add (new Cat ());
        animals.add (new Dog ());

        discuss (animals);
        upTheTree (animals);
    }

    public static void discuss (List <Animal> animals) {
        for (Animal a : animals)
            a.talk ();
    }

    public static void upTheTree (List <Animal> animals) {
        for (Animal a : animals) {
            if (a instanceof TreeClimbing)
                ((TreeClimbing) a).climbToATree ();
        }
    }
}

We don't need a third animal, dog and cat are enough. I made them default visible instead of public, to make the whole example fit into a single file.

like image 39
user unknown Avatar answered Oct 09 '22 02:10

user unknown