DEV Community

Cover image for Due to the if-else and switch statements ,run time polymorphism exist in this world !!!
Viraj Guranna Yalawar
Viraj Guranna Yalawar

Posted on

Due to the if-else and switch statements ,run time polymorphism exist in this world !!!

Yes, you heard it right. The reason that run-time polymorphism exists in programming is due to the decision-making statements that exist in programming. To understand that, quickly, we will understand the following terminologies:

Compile time: is the time when the compiler is scanning each line of code and converting it to the machine-level instructions.

Run time: is the time when the machine is executing the instructions in a proper order as decided by the compiler.

Method binding: is the process of binding the function call with the implementation of a method.

In method overloading, beforehand only, we write the implementations of all the required methods with different number of parameters or different data types .

In method overriding also, we write the implementation beforehand only; for example, in a derived class, we write the complete implementation of the method of the base class, which needs to be overridden by the derived class.

So it is mandatory that both types of methods get compiled before the execution of the main function.

Method Overloading

If we consider the case of method overloading, we know that at compile time only, the machine gets to know whether there are two parameters, three parameters, or whether it needs to differentiate the data types and bind the correct method with the line having the method call in the main method, out of the other implementations of the same method.

For example:

int func1() {

    // ...

}

void func1(int a, int b) {

    // ...

}
Enter fullscreen mode Exit fullscreen mode

If the compiler sees the func1(); function call at compile time, then it will bind that call with the int func1(){.....} definition.

If the compiler sees func1(a,b); at compile time, then it will bind that call with the void func1(int a,int b){.....} definition.

Method Overriding

If we consider the case of method overriding, at compile time only, the machine gets to know which object is getting instantiated, like base or derived.

For example, we write:

BaseClass object = new DerivedClass();

object.Func1();
Enter fullscreen mode Exit fullscreen mode

We know that the compiler is not that dumb. It can easily differentiate the words DerivedClass and BaseClass, and it has that much sense to bind the method present inside DerivedClass with the function call object.func1(); at compile time itself, but why doesn't it bind at that time and waste time in binding that at run time?

Imagine if we do so, then both become compile-time polymorphism only, and we will not have any confusion in studying run-time and compile-time polymorphism.

Why doesn't Java do that? Why does Java confuse us with run-time and compile-time polymorphism?

The answer to that question is explained below.

In fact, modern Java compilers and the Just-In-Time (JIT) compiler do exactly what we argued above. It is called Monomorphic Inline Caching or Devirtualization. When the compiler sees the object creation right next to the function call to the same object, then it bypasses the runtime lookup and binds it directly at compile time to save performance.

But when an object is created inside if-else or switch-case statements, then it becomes impossible to bind the function call with the method at compile time. To understand this, look at the gaming example given below.

I will explain that with the simple example.

Overloading Example

void weapon(String rightHand) { ... }                         // Method A

void weapon(String rightHand, String leftHand) { ... }       // Method B


// main method code

int choice = getPlayerInput(); // Input happens at runtime

if (choice == 1) {

    weapon("swordInRightHand"); // function call 1

} else {

    weapon("gunInRightHand", "swordInLeftHand"); // function call 2
}

// there are two function calls
Enter fullscreen mode Exit fullscreen mode

Overriding Example

// assume Weapon is the base class and SwordInRightHand,
// gunInRightHandAndSwordInLeftHand as derived classes

int choice = getPlayerInput(); // User presses a button on their keyboard at runtime

if (choice == 1) {

    Weapon weapon = new SwordInRightHand();

} else {

    Weapon weapon = new gunInRightHandAndSwordInLeftHand();
}

weapon.attack(); // only one function call present

// The compiler looks at this line at compile time, but it was not aware of which control statement gets executed in the future.
// So it won't bind this line with either SwordInRightHand()
// or gunInRightHandAndSwordInLeftHand() ......!
Enter fullscreen mode Exit fullscreen mode

We note that in the example of overloading, we have two different function calls for two different definitions, but in the example of overriding, we have only one function call which can be bound to two different definitions.

So in overloading, the compiler easily identifies that there are two function calls, and it also finds the respective two different implementations.

But in the example of overriding, the compiler successfully gets to know that there are two different implementations, but it has only one function call.

So that's the reason it leaves the binding of the method with the function call at run time and gives privilege to the machine to bind the function call with that method by analysing which class object is created at run time.

As Java is the broader language, and sometimes run-time decisions are made even without the explicit use of decision-control statements in many other cases, explaining that further will increase the size of the article.

So in this, I am just using decision-control statements as a major reason for the existence of run-time polymorphism.

I hope this article is helpful in understanding the difference between run-time and compile-time polymorphism.

Thank you so much.......

Top comments (0)