Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

This question already has an answer here:

I understand what Polymorphism is, but since I only ever programmed in Java and 'dived' pretty quickly into OOP, I'm having a hard time understanding exactly what it's benefits are (and I feel the same about a lot of other OOP principles and concepts).

Please explain to me how the OO programmer benefits from Polymorphism, and what exactly it's good for. Comparing it with procedural code that does pretty much the same thing but without Polymorphism, will also be helpful.

EDIT: To clarify, I'm referring to the kind of Polymorphism that allows you to operate generically on an object, without having to know or depend on it's specific type.

For example, consider a class Person. It implements several methods, one of them eat(). It has two subclasses, Child and Adult. I have a collection of objects that can be of type Person, Child or Adult. And I want them all to eat. Using Polymorphism, I can call eat() on any one of them without caring about it's specific type or having to implement logic to specifically make an adult eat or a child eat.

This kind of Polymorphism is mainly what I am referring to.

However I gave a very generic example for it's benefits, and I still don't understand completely why - 'in the real world' - it's such a big improvement as opposed to not using Polymorphism.

(Again, I know what Polymorphism is and how to use it in a program, but since I have no experience in programming in a non-OO style, I can't compare working with Polymorphism to not using it and thus can't understand it's benefits completely).

share|improve this question

marked as duplicate by gnat, Bart van Ingen Schenau, GlenH7, ChrisF Apr 30 at 21:22

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

4  
Which type of polymorphism are you referring to? –  Robert Harvey Apr 24 at 17:34
    
@RobertHarvey See my edit please. –  Aviv Cohn Apr 24 at 17:41
1  
What if there were a hundred different ways to eat? Would you really want to have to make a unique method call for each one (i.e. AlligatorEat(food), BirdEat(food)), or would it be far more convenient to just say object.eat(food), and let the object figure out how? –  Robert Harvey Apr 24 at 17:45
3  
Polymorphism is in no way limited to OOP; Functional Programming languages can support extreme polymorphism while completely doing away with subtype polymorphism known from OO; in fact, I'd say that is the main advantage of FP languages such as Haskell, Scala, OCaml and others. –  Erik Allik Apr 24 at 18:01
2  
If all you ever build are small sheds, you'll never know why skyscrapers are made out of steel and concrete and have to adjust for the wind. –  JeffO Apr 24 at 19:10

4 Answers 4

up vote 10 down vote accepted

The primary benefit of polymorphism is freedom.

When an object has a reference to another, it can invoke methods on that object reference without knowing, or caring, what the implementation is.

So it allows you to make the powerful statement: Don't know, don't care.

How does this object implement this interface? Don't know, don't care. How many different implementations are there? Don't know, don't care. In this list of things, how many are one thing and how many are another? Don't know, don't care.

So polymorphism (the classic subtype polymorphism) gives you a high degree of freedom and decoupling because the implementation behind an interface is hidden from the clients. At coding time, you only have to worry about programming to the interface. At test time, you can naively substitute a mock object & validate your unit of code independently. At run time, you can dynamically supply different implementations based on application logic in order to achieve late binding.

Note there are other types of polymorphism, see this article at Wikipedia, such as "parametric polymorphism" which is a way of defining wrappers or containers, that are also very powerful. But the common idea of polymorphism is some common interface that abstracts and hides the details of the implementation. And that hiding or decoupling is what enables clean, decoupled design, and developing pieces of extremely large systems in isolation.

...

I think the closest equivalent in procedural programming would be passing around function pointers (if your language allows that). In OO, the function pointers as well as the related data (i.e. the state) get bundled up in a logical unit. So like almost everything else ;) you can do OO design in a procedural language, you just have to work a little harder. (Which, come to think of it, is polymorphism too.)

Barring that, you'd have to fall back to a bank of if-then statements, one for each of the implementations you want. That would get increasingly big and messy over time.

The upshot is that polymorphism allows the language to dynamically dispatch the request to the right implementation at runtime, saving you the trouble (and extra lines of code) that you'd need in a procedural language.

...

One more thought. We usually talk about "scaling" in terms of "scaling to load". That is, as I get millions and millions of users, how will I scale my app to handle them all? But there's another critical aspect of scaling that we almost never talk about explicitly for some reason: scaling to complexity. Over time, your program will increase, and will almost never decrease, in complexity. You're always adding new features and functionality. Polymorphism is a critical, and central, mechanism for scaling a system's complexity, because it allows abstraction and economies of scale in client/server contracts, and also allows for the (sane) extension of functionality, because you can always add new implementations over time.

For example, what if you need to model a lactose-intolerant Adult at some point? In addition to Child.eat() and Adult.eat(), you can model LactoseIntolerantAdult.eat() without necessarily changing the rest of your system.

share|improve this answer
4  
Mentioning the Liskov Substitution Principle would be useful here, so as to shed light on the dangers of overuse/misuse of subtype polymorphism. –  Erik Allik Apr 24 at 18:03
    
A bit tangential, but the key detail to parametric polymorphism is that the code doesn't rely in any way on the type of certain values. E.g. a function that simply returns its argument is (parametrically) polymorphic in the type of its argument because it doesn't need to know anything about the type to do its work. In this case the polymorphism isn't related to multiple implementations having the same signature, because there isn't necessarily an alternative implementation. For reference, Java and C#'s generics are a watered down form of parametric polymorphism. –  Doval Apr 24 at 18:05
    
@Doval ya, I was trying to get at the central idea of polymorphism, and "common interface" in the broadest sense of interface possible was what I came up with. But it's a bit of a stretch. In the case of parametric polymorphism, the container is the interface and it hides the detail of the contained type. Anyway, I linked wiki to cover my bases ;) –  Rob Y Apr 24 at 18:09
1  
@Doval lol and function overloading is just "ad hoc polymorphism" So there :P –  Rob Y Apr 24 at 18:23
1  
I am working as a client of a package containing a large set of classes that have various inheritances. It is coded so that I can have a pointer or reference to any type in that tree and call the dump() method to see the contents as part of my debugging. It is extremely easy for me as a client to debug this code because it will show me the data for everything down to the leaf, even if my pointer is to a type high up in the inheritances tree. –  Michael Mathews Apr 24 at 21:32

The accepted answer provides a good explanation, but I wanted to provide some insight with code examples.

I think the Java Collections framework is a good example. Let us assume we have a method that needs to take a group of objects and perform some action on all of them. We could certainly provide a method such as this one:

public void foo(ArrayList<Widget> objects) {
  for (Widget obj : objects) {
    obj.frobnicate();
  }
}

As long as someone has an ArrayList containing Widgets, all is good.

Wait a minute, what if the user needs to pass in a LinkedList because random access is not required? Well, we are not calling any methods specific to ArrayList, and the iteration is in order, so maybe we can go up a level to List:

public void foo(List<Widget> objects) {
  for (Widget obj : objects) {
    obj.frobnicate();
  }
}

Now the method takes any type of List and is more flexible. Just wait another minute! Now the user is telling us they do not want to frobnicate a widget twice, that could break something! They must be able to use a Set, which guarantees an item can only appear once. So we implement another method:

public void foo(Set<Widget> objects) {
  for (Widget obj : objects) {
    obj.frobnicate();
  }
}

Great, except now there is duplication. The code is doing the same thing but on different types. Perhaps there is a higher level interface? Yes, there is! Replace both of the prior implementations with this one:

public void foo(Collection<Widget> objects) {
  for (Widget obj : objects) {
    obj.frobnicate();
  }
}

This is great until we need compatibility with some other custom data structure. For example, a data structure that operates on terabytes of data that cannot fit in memory all at once (think about updating all records in a large database table, for example). Well, there is one more layer to this onion:

public void foo(Iterable<Widget> objects) {
  for (Widget obj : objects) {
    obj.frobnicate();
  }
}

Now the code maximizes polymorphic behavior. If you have a small ArrayList that guarantees order and random access, a large TreeSet that guarantees uniqueness and order, or some other data structure with its own properties, none of that matters. Our code only needs to iterate a data structure and frobnicate its contents. Implementation details do not matter, only that our data structure can iterate.

share|improve this answer

You asked for a real world example, so I'll provide one.

I'm currently engaged in work that utilizes

  • cameras
  • optics
  • machine learning
  • classification of different traits for specific objects
  • abstracting all of the above for someone else to use in a GUI

This requires classic polymorphism for maintenance, and for better design. For instance, what happens when the camera manufacturer builds a new camera type in the future? We want to be able to make a new derived class/object that will work with that camera, but not have code which depends on that camera depend on the camera type! If it did, when a new camera is used, all dependent code would have to be rewritten.

Similarly, suppose that I design a new-fangled classification algorithm, or want to test the performance of many different algorithms, then I don't want to have the classification output and interaction with the classification algorithm be different for each algorithm type. I want to be able to easily test performance by substituting different algorithm types easily and efficiently, which polymorphism is a natural fit for. I can hide the implementation of the different types from the code which checks for performance, or otherwise interacts with the classification algorithms.

In the above examples, if I didn't use polymorphism, then a change in camera type, for example, would likely require a change in all code that depends on the current camera to use the new camera. This can be tedious and time consuming. It can also introduce bugs (some line of code is not changed to use the new camera type). With polymorphism, all I have to do give dependent code a different camera type, and it will still be able to use the new camera type.

For large projects which need different components interacting, polymorphism is a very useful tool for future proofing, and for minimizing the amount of code that needs refactoring when something changes...

share|improve this answer
    
Wow. I was going to write damn near the exact same real world example! I too develop machine vision software & inspection systems. From the abstraction of the cameras to the algorithms, I do the exact same thing. –  Dave Nay Apr 26 at 23:20

Originally, there was some limitations attached to each type. For example, in C++, sizeof(T) is calculated in compile-time. Thus the size of each type is fixed long before runtime. To account for types where size of the type changes on runtime, polymorphism is needed. Same kind of limitations there is for number of functions available in the type. If the functions change on runtime, again, polymorphism is needed.

Note, the low level view of a type looks like this:

 (0101010)(0110101010110)(1010101010110)(101010101011)(1010101011)  Type A

The only thing you can do is change where the ()'s are in; and this is fixed in compile-time. Polymorphism gives you ability to replace part of the ()'s with another assignment of ()'s. And even length of the bit sequence can change when using polymorphism.

Polymorphism in low level looks like this:

  (0101010)                Type Base
  (0101010)(01)            Type A : Base
  (0101010)(010101)        Type B : Base
  (0101010)(0101010101)    Type C : Base
  (0101010)(01010)(101010) Type D : Base

Ability to switch between them in runtime is the defining feature of polymorphism; same algorithm works with all the bit sequences.

share|improve this answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.