Object oriented programming is a rabbit hole where polymorphism is just another thread in the hole, let’s see how deep can it go.
This article will take you on a journey to unravel the mystery of compile time polymorphism . Plus in
C# We have just the right material to make it worse, with method overloading and overriding, we also have the concept of method of hiding, which makes the whole idea of polymorphism a bit baffling. And that’s why I am going to clear the confusion by breaking down the idea into 3 parts.
This is a series of 3 articles where we are going to take a deep dive into polymorphism. The following are the 3 pieces of the puzzle.
- Compile-time polymorphism
- Run-time polymorphism
- Method hiding/ shadowing
Because the compiler knows which method to call at compile time based on method’s signature. This dependency is solved at compile time. Ok! This sounds good in theory but let’s see how it works practically.
HOLD ON SEC!!, what did you mean by method signature, though?
Well, there are 4 pieces to any method.
- Method name,
- return type,
- The return type
There is a huge argument between the developer’s community, whether return type should be part of method signature or not!!
How about we clear that confusion from Microsoft?
As per Microsoft, “A return type of a method is not part of the signature of the method for the purposes of method overloading. However, it is part of the signature of the method when determining the compatibility between a delegate and the method that it points to”.
In simple words, while “overriding a method”, return type is taken into consideration as a part of method signature.
While “overloading a method”, it is simply ignored.
Let’s understand polymorphism step by step with actual coding and with coding examples we will learn the behaviors to support the argument above.
There are a few rules you need to be aware of while overloading a method.
Typeof parameters should be different, and the name of the parameter doesn’t matter.
- Number of parameters should be different.
- Order of the parameters should be different.
- Last but not the least,
access specifiersor any of other fancy keywords such as
virtualare not taken into consideration.
To demonstrate these rules, I am going to code following UML throughout the article, this will touch upon almost all the aspects of method overloading.
Imagine we are designing a
class superhero in which our task is to customize a suit. There could be different arguments coming into play, color of the suit, type of suit, or whether the hero likes to wear his underwear out or not etc. Let us go ahead and design a class to fulfill these points.
In the following code snippet, we are designing a suit for a “Superman”.
This code works as long as you want your default superhero to-be superman. But let’s face the fact, he ain’t that great. So in order to customize a suit for another superhero, we can create a separate
typeOfSuit and I want to customize that, it could be a leather or a metal suit. In order to code this I can simply create a method which will accept one
string type parameter which would be
Rule #1: Type of parameter/s should be different, the name of the parameter/s doesn’t matter.
My superhero expresses an interest in a metal suit, now he obviously can’t wear underwear on the top of it. So I can simply overload the
CustomizeSuit() method to accept different type of parameter. In here, we are overloading a method which accepts
boolean typeif the value of this parameter
true then our hero is going to wear an underwear outside else inside.
Rule #2: Number of parameters should be different.
Some users want to either want to customize the type of suit or decide the placement of the underwear but others might be interested in changing both together. We can achieve this simply by overloading a method with a different number of parameters.
Rule #3: Order of the parameters should be different.
You can have the same number of parameters but the order must be different, for example I can take code from
listing 4 and do this.
Listing 5 explanation: I just interchange the order of parameters in listing 5. Compiler looks for the index of the parameter and its type. If
Type is different at the same index then it’s a valid overloaded method.
Another variation could be as listing 6
Rule #4: Last but not the least , return type, access specifiers or any of other fancy keywords such as static, abstract, sealed, virtual means nothing.
Let’s go fully wild on that one, shall we?
Rule #4.1: Return type is not taken into consideration.
In the following example everything is the same between 2 methods, except the
return-type. If you have 2 methods with the same signature but different
return-type, it is not considered as method overloading. Compiler will throw a compile-time exception.
The Exception: Type
‘SuperHero’ already defines a member called
‘CustomizeSuit’ with the same parameter types.
Rule #4.2: Access specifiers are ignored
Well rule 4.1 was pretty cool, Now for rule number 4.2, we need to change the access specifiers.
Same good exception!!
Rule #4.3: Special keywords are ignored
In the following snap you would see, none of the keywords are working with an overloaded method. So a method with these keywords means nothing to the concept of overloading.
Note: For the abstract method, I’ve marked class as abstract.
Above all methods falls under the same exception.
‘SuperHero’ already defines a member called
‘CustomizeSuit’ with the same parameter types
We have come a long way with method overloading, there is one more important concept I would like to throw in there as a bonus point.
The following code snippet is a parent
class SuperHero. It contains every overloaded method that we’ve discussed so far.
Let’s create a child class which will inherit the parent
class IronMan is the child of
class SuperHero. which is very elegantly overloading a
CustomizeSuit() method with 3 parameters.
Yeah!! You heard it right, method overloading is not restricted within a same class.
I have created an instance of both parent and a child class. Have a look at the following image 5, I get 4 overloaded methods with parent’s object.
Let’s see what number we get when we try to call
CustomizeSuit() with a child’s object. As you can see in the image 6, child class AKA
IronMan has one more extra count, which is referring to the method we just created in listing 10. Hence proved, you can actually overload a method from different classes.
Even though I can overload a parent’s method in a child class, still there is one thing we should be aware of.
Note: The four rules that I mentioned above are only applicable within the same class.
Let’s not get confused here! Let me demonstrate this with an example. Have a look at the following two images 7 and 8.
In the image below, the
CustomizeSuit() method is defined in
class SuperHero and the same method is again defined in
class IronMan and it seems the compiler has no problem with it.
class SuperHero will call the it’s own version of
CustomizeSuit() methodand object of
class IronMan would have extra count overloaded method but it will still call its own implementation of
So point being, you can have the same signature of an overloaded method only if you are in a different type.
But you can’t have the same signature within the same type.
Look, how compiler reacts in image 8. It gives me an error when I am overloading a method with the same signature within the same
class. So remember those four rules are applicable within the same
Yes, Method overloading could be quite overwhelming, when we try to cover all the possibilities but once you have the basics fundamentals clear you will be able to understand its purpose in object oriented programming. In this article we deep dived covering all aspects with different examples to understand what is acceptable and what is not when it comes to compile time polymorphism.
Want to Connect?Hit me up on LinkedIn.