Is Polymorphism Possible Without Inheritance

Is polymorphism possible without inheritance?

The best explanation on the subject that I've ever read is an article by Luca Cardelli, a renown type theorist. The article is named On Understanding Types, Data Abstraction, and Polymorphism.

Types of Polymorphism

Cardelli defines several types of polymorphism in this article:

  • Universal
  • parametric
  • inclusion
  • Ad-hoc
  • overloading
  • coercion

The kind of polymorphism related to inheritance is classified as inclusion polymorphism or subtype polymorphism.

Wikipedia provides a good definition:

In object-oriented programming, subtype polymorphism or inclusion
polymorphism is a concept in type theory wherein a name may denote
instances of many different classes as long as they are related by
some common super class. Inclusion polymorphism is generally
supported through subtyping, i.e., objects of different types are
entirely substitutable for objects of another type (their base
type(s)) and thus can be handled via a common interface.
Alternatively, inclusion polymorphism may be achieved through type
coercion, also known as type casting.

Another Wikipedia article called Polymorphism in object-oriented programming seems to answer your questions as well.

In Java

This subtyping feature in Java is achieved, among other means, through the inheritance of classes and interfaces. Although the subtyping features of Java may not be evident in terms of inheritance all the time. Take for example the cases of covariance and contravariance with generics. Also, arrays are Serializable and Cloneable although this is not evident anywhere in the type hierarchy. It can also be said that through primitive widening conversion the numeric operators in Java are polymorphic, in certain cases even accepting totally unrelated operands (i.e. concatenation of strings and numbers or of a string plus some other object). Consider also the cases of boxing and unboxing of primitives. These latter cases of polymorphism (coercion and overloading) are not at all related to inheritance.

Examples

Inclusion

List<Integer> myInts = new ArrayList<Integer>();

This is the case to which your question seems to refer i.e. when there is an inheritance or implementation relationship between the types, as in this case where ArrayList implements List.

As I mentioned, though, when you introduce Java generics, some time the rules of subtyping get fuzzy:

List<? super Number> myObjs = new ArrayList<Object>();
List<? extends Number> myNumbers = new LinkedList<Integer>();

And in other cases, the relationships are not even evident in the API

Cloneable clone = new int[10];
Serializable obj = new Object[10]

Even so, all these, according to Cardelli, are forms of universal polymorphism.

Parametric

public <T> List<T> filter(Predicate<T> predicate, List<T> source) {
List<T> result = new ArrayList<>();
for(T item : source) {
if(predicate.evaluate(item)){
result.add(item);
}
return result;
}
}

The same algorithm can be used to filter all kinds of lists with all kinds of predicates without having to repeat a single line of code for every possible type of list. The type of the actual list and the type of predicate are parametric. Like in the following examples with Java lambda expressions.

filter(x -> x % 2 == 0, asList(1,2,3,4,5,6)); //filters even integers
filter(x -> x % 2 != 0, asList(1L,2L,3L,4L,5L,6L)); //filters odd longs
filter(x -> x >= 0.0, asList(-1.0, 1.0)); //filters positive doubles

According to Cardelli, this is a form of universal polymorphism.

Coercion

double sum = 1 + 2.0;

Integer and floating-point arithmetic are totally different. Applying the plus operator to two operands of different types here is impossible without some form of coercion.

In this example, the types integer and double, are automatically coerced (converted) to type double without an explicit cast. The entire expression is promoted to double. This is so because in Java we have primitive widening conversions.

According to Cardelli, this form of automatic coercion is a form of ad-hoc polymorphism provided for the plus operator.

There are languages in which you could not even sum an integer and a floating-point number without an explicit cast (i.e. AFAIK, SML, in which, by the way, parametric polymorphism is key to overcome this kind of problems).

Overloading

double sum = 2.0 + 3.0;
String text = "The sum is" + sum;

The plus operator here means two different things depending on the arguments used. Evidently, the operator has been overloaded. This implies it has different implementations depending on the types of operands. According to Cardelli, this is a form of ad-hoc polymorphism provided for the plus operator.

This, of course, also applies to forms of method overloading in classes (i.e java.lang.Math methods min and max are overloaded to support different primitive types).

In Other Languages

Even when inheritance plays an important role in the implementation of some of these forms of polymorphism, certainly it is not the only way. Other languages that are not object-oriented provide other forms of polymorphism. Take, for example, the cases of duck typing in dynamic languages like Python or even in statically-typed languages like Go, or algebraic data types in languages like SML, Ocaml and Scala, or type classes in languages like Haskell, multi methods in Clojure, prototypal inheritance in JavaScript, etc.

Is inheritance necessary for encapsulation, abstraction and polymorphism?

  • Is Encapsulation possible without inheritance?

Yes, because Encapsulation is the ability to hide a class properties from the outside world by means of access methods.

  • Is Abstraction possible without inheritance?

Well, abstraction can refer to many things, but talking about OOP:
No, an abstract class cannot be used directly, you can only instantiate inherited classes.

  • Is Polymorphism possible without inheritance?

Yes, polymorphism is the construction of a single interface to several types of objects, for instance, a single function call that can receive different classes or data types as arguments. They can be inherited or not.

What is the main difference between Inheritance and Polymorphism?

Inheritance is when a 'class' derives from an existing 'class'. So if you have a Person class, then you have a Student class that extends Person, Student inherits all the things that Person has. There are some details around the access modifiers you put on the fields/methods in Person, but that's the basic idea. For example, if you have a private field on Person, Student won't see it because its private, and private fields are not visible to subclasses.

Polymorphism deals with how the program decides which methods it should use, depending on what type of thing it has. If you have a Person, which has a read method, and you have a Student which extends Person, which has its own implementation of read, which method gets called is determined for you by the runtime, depending if you have a Person or a Student. It gets a bit tricky, but if you do something like

Person p = new Student();
p.read();

the read method on Student gets called. Thats the polymorphism in action. You can do that assignment because a Student is a Person, but the runtime is smart enough to know that the actual type of p is Student.

Note that details differ among languages. You can do inheritance in javascript for example, but its completely different than the way it works in Java.

What can polymorphism do that inheritance can't?

What can polymorphism do that inheritance can't?

The real advantages of Polymorphism can be seen at runtime rather than compile time. Polymorphism allows you to substitute one implementation for another without the need to change the code that uses it. Let's take your example of the Animal hierarchy. Let's say you have a Vet that knows how to perform health checkups on any animal (Yup he's a supervet).

class Vet {
private Animal animal;
public Vet(Animal animal) {
this.animal = animal;
}

public void perfromCheckup() {
animal.talk();
animal.poop();
}
}

You can now say :

Vet vetWithBird = new Vet(new Bird());
Vet vetWithDog = new Vet(new Dog());
vetWithBird.performCheckup();
vetWithDog.performCheckup();

Notice how you can tell the Vet to perform a checkup on a Bird or a Dog or any other animal for that matter without needing to change your Vet class. At runtime, the Dog would bark when it goes for a checkup and the Bird would tweet when it goes for a checkup. Imagine if instead of Animal, the Vet had a Bird reference :

class Vet {
private Bird bird;
public Vet(Bird bird) {
this.bird = bird;
}

public void perfromCheckup() {
bird.talk();
bird.poop();
}
}

The poor Vet is now only going to be able to work with a Bird. Tell your Vet to work with a Dog and he will reject this right away.

Vet vetWithBird = new Vet(new Bird()); //Works fine. Vet likes birds.
Vet vet = new Vet(new Dog())// compilation error. Sorry I don't like dogs.

In summary, Polymorphism allows you to substitute subclass instances where a super-class reference is used. Inheritance allows you to inherit code from a parent class and possibly redefine that behavior in subclasses so that your code can take advantage of it at runtime through Polymorphism

Isn't polymorphism just a side effect of inheritance?

You are correct that in most OO languages, inheritance and polymorphism go one with another. But:

  1. Polymorphism and Inheritance both illustrate different aspects. Polymorhpism shows how the types can stand one for another in operations, while the inheritance shows the relationship between the types.
  2. Polymorphism and Inheritance don't have to go together in general. If you look at integer and float numbers for example, there all of them can stand at the same places of arithmetic expression, so it is in fact polymorphism, but there is no inheritance. Also, inheritance is possible without polymorphism.

C++ : inheritance without virtuality

Not using virtual members/inheritance is perfectly ok. C++ is designed to entertain vast audience and it doesn't restrict anyone to particular paradigm.

You can use C++ to code procedural, generic, object-oriented or any mix of them. Just try to make best out of it.

I'm currently doing is a shame for C++, or if it is OK.

Not at all.

Rather if you don't need OO design and still imposing it just for the sake of it, would be a shame.

Basically, I want to use this classes without pointers or redirection ...

In fact you are going in right direction. Using pointers, arrays and such low level features are better suited for advance programming. Use instead like std::shared_ptr, std::vector, and standard library containers.

Is polymorphism an imminent side effect of inheritance?

Can inheritance exist without Polymorphism?

They are related concepts, but yes, it is possible to have one without the other. In Java if you subclass a parent class you also get a subtype, but in other languages this might not be the case implicitly. In some languages inheritance can be just a form of code reuse.

For example, in C++ you don't get polymorphism if you don't mark your methods virtual. See here for an explanation: Why do we need Virtual Functions in C++?. In Java on the other hand, all public methods are implicitly virtual.

This is a vast subject that has many flavors in many languages. As a TL;DR (and a gross gross gross simplification) you can think inheritance is a form of code reuse while polymorphism is the ability to substitute an object of a type with an object of a subtype and your program continues to work correctly. In Java these two things overlap and you get one from the other but not all languages are like that.

And even if you get polymorphism out of the box from inheritance it is still possible to "break polymorphism" by not respecting the Liskov substitution principle. Like I said... a vast subject.

What is polymorphism in Javascript?

Polymorphism is one of the tenets of Object Oriented Programming (OOP). It is the practice of designing objects to share behaviors and to be able to override shared behaviors with specific ones. Polymorphism takes advantage of inheritance in order to make this happen.

In OOP everything is considered to be modeled as an object. This abstraction can be taken all the way down to nuts and bolts for a car, or as broad as simply a car type with a year, make, and model.

To have a polymorphic car scenario there would be the base car type, and then there would subclasses which would inherit from car and provide their own behaviors on top of the basic behaviors a car would have. For example, a subclass could be TowTruck which would still have a year make and model, but might also have some extra behaviors and properties which could be as basic as a flag for IsTowing to as complicated as the specifics of the lift.

Getting back to the example of people and employees, all employees are people, but all people are not employees. Which is to say that people will be the super class, and employee the sub class. People may have ages and weights, but they do not have salaries. Employees are people so they will inherently have an age and weight, but also because they are employees they will have a salary.

So in order to facilitate this, we will first write out the super class (Person)

function Person(age,weight){
this.age = age;
this.weight = weight;
}

And we will give Person the ability to share their information

Person.prototype.getInfo = function(){
return "I am " + this.age + " years old " +
"and weighs " + this.weight +" kilo.";
};

Next we wish to have a subclass of Person, Employee

function Employee(age,weight,salary){
this.age = age;
this.weight = weight;
this.salary = salary;
}
Employee.prototype = new Person();

And we will override the behavior of getInfo by defining one which is more fitting to an Employee

Employee.prototype.getInfo = function(){
return "I am " + this.age + " years old " +
"and weighs " + this.weight +" kilo " +
"and earns " + this.salary + " dollar.";
};

These can be used similar to your original code use

var person = new Person(50,90);
var employee = new Employee(43,80,50000);

console.log(person.getInfo());
console.log(employee.getInfo());

However, there isn't much gained using inheritance here as Employee's constructor is so similar to person's, and the only function in the prototype is being overridden. The power in polymorphic design is to share behaviors.



Related Topics



Leave a reply



Submit