Polymorphism in object oriented systems - codecentric AG Blog

:

I recently had a quite interesting discussion at the office. I was sitting together with some colleagues learning the Go programming language, when we started to discuss about the term “polymorphism”. It was very fascinating to see that we had at least three different views on what exactly polymorphism is. Since my understanding of polymorphism differed a bit from that of the others, I’d like to share it with you. I’m also interested to hear what you think about this topic.

Polymorphism and inheritance

A common definition a polymorphism is tied closely to the concept of inheritance in object oriented programming languages (this following one is from wikipedia):

“Subtyping (or inclusion polymorphism) is a concept wherein a name may denote instances of many different classes as long as they are related by some common superclass. In object-oriented programming, this is often referred to simply as polymorphism.”

Let’s make this a bit more explicit with an example. Consider the following code:

public abstract class Person {
   abstract String getName();
}
 
public class Student extends Person {
   @Override
   public String getName() {
      return "Peter";
   }
}
 
public class Professor extends Person {
   @Override
   public String getName() {
      return "Professor Smith";
   }
}
 
public class App {
 
   public static void printName(Person person) {
      System.out.println(person.getName());
   }
 
   public static void main(String... args) {
      Student student = new Student();
      Professor professor = new Professor();
 
      printName(student);
      printName(professor);
   }
}

public abstract class Person { abstract String getName(); }public class Student extends Person { @Override public String getName() { return "Peter"; } }public class Professor extends Person { @Override public String getName() { return "Professor Smith"; } }public class App {public static void printName(Person person) { System.out.println(person.getName()); }public static void main(String... args) { Student student = new Student(); Professor professor = new Professor();printName(student); printName(professor); } }

In this example the name person in the printName(Person) method may denote instances of different classes (namely of Student and of Professor). This works since both inherit from the Person class which defines the getName() method. The compiler makes sure that all subclasses have a getName() method.

Now consider the following code:

public class Dog {
   public String getName() {
      return "Pluto";
   }
}

public class Dog { public String getName() { return "Pluto"; } }

The Dog class doesn’t inherit from Person – a dog is not a person. But all dogs usually have a name so it makes sense to define a getName() method for dogs as well. Since Java is a statically typed language, we can not pass instances of Dog to the printName(Person) method, although instances of Dog provide the interface needed by printName(Person) (which is a method with name “getName” with no input parameters that returns a String). Polymorphism in Java is tied closely to inheritance.

Another problem with our definition of polymorphism is, that it requires the concept of classes. What would you say: Does for example JavaScript provide polymorphism? We have defined polymorphism by means of inheritance between classes. Since JavaScript doesn’t provide classes, it looks like there can not be support for polymorphism in JavaScript.

Polymorphism without inheritance

Now let’s broaden our view on the problem a bit. Let’s rewrite our example using JavaScript:

var student = {
   getName: function() {
      return "Peter";
   }
};
 
var professor = {
   getName: function() {
      return "Professor Smith";
   }
};
 
var printName = function(param) {
   console.log(param.getName());
};
 
printName(student);
printName(professor);

var student = { getName: function() { return "Peter"; } };var professor = { getName: function() { return "Professor Smith"; } };var printName = function(param) { console.log(param.getName()); };printName(student); printName(professor);

Although we neither have inheritance nor classes in JavaScript it looks like the printName(param) function behaves polymorphic (yes I know there is prototypical inheritance in JavaScript, but let’s keep it simple ;-)). What happens if we add a dog object to our code?

var dog = {
   getName: function() {
      return "Pluto";
   }
};

var dog = { getName: function() { return "Pluto"; } };

Can we pass the dog to printName(param)? Of course we can since JavaScript is dynamically typed! It would simply print out “Pluto”.

A broader definition of polymorphism

This example leads to a broader definition of polymoprhism that is not bound to the concepts of inheritance and classes, but only to what lies at the heart of object orientation: Objects, that exchange messages with each other.1

“Wait a minute… Objects exchanging messages?” you say
“Yes of course!” I reply.

The following call in Java:

can be translated into sending the object referenced by “pers” the message “give me your name”. The object in turn decides whether it can handle that message. In Java the compiler makes sure that you only use messages the objects you’re working with can handle – you simply can’t compile code that calls methods that aren’t defined. In dynamically typed languages you can send any message to an object, not knowing if it can actually handle the message. In our example the object answers the message by returning the result of calling the getName() method.

So my proposal for a definition of the term polymorphism is:

“Polymorphism in an object oriented system is the ability of different objects to respond to the same message with different answers.”

By this definition the code in the Java printName(Person) method can send the message “give me your name” to its input parameter. Different objects inheriting from Person may return different answers to this message. The compiler enforces that only objects that can handle the message may be passed to printName(Person).

The JavaScript function printName(param) on the other hand does also send the message “give me your name” to it’s input parameter. But in JavaScript there is no static typing, no compiler enforcing parameter types and hence no need for a common super class. As long as the objects passed to the function can handle the message “give me your name”, everything will work fine. If for some reason an object which can not handle the message is passed to printName(param) it will blow up at run time.

This definition of polymorphism is not tied to classes or inheritance. It can be applied to statically typed languages that provide inheritance like Java, as well as to dynamically typed languages like JavaScript. In other words: Polymorphism is not tied to inheritance! To the contrary the fact that you can only make use of polymorphism by using inheritance is a restriction of statically typed languages.

Footnotes

1. Have you ever asked yourself what the core concepts of object orientation are? Talk to your collegues and ask them what concepts are part of object orientation. I’m sure you’ll get very different answers. The truth is, that there is no formal definition of what object orientation is. A very good reading about this is Armstrong DJ (2006) The quarks of object-oriented development in Communications of the ACM 49(2):123–128 – I recommend it to everybody who works in object oriented systems.