A brief introduction to polymorphism for beginners
Tags: beginners, oop, csharp
Published: 2022-05-12 05:31:25

In this blog, we're going to take a look at polymorphism – what it is,  how you can use it in your code and the advantages of using polymorphism. Polymorphism can be a tricky concept to understand at first, but it's an incredibly powerful tool that can help improve the performance of your code and make development easier on large-scale projects. Let's get started!

**What is polymorphism**
Polymorphism is a Greek word that means "many forms". In object-orientated development, objects can be of many forms, but what do we mean by this? Well, an example can be a dog, a dog can be in many different forms,it can be a poodle or a bulldog. But they are all still dogs and have certain features that are the same, for example they can all bark.

Polymorphism is often used in conjunction with inheritance, but it's important to note that they are two different concepts. Inheritance allows you to create subclasses that inherit the attributes and methods of a parent class. On the other hand, polymorphism enables you to write code that can work with any object, regardless of its specific type, when the classes are related to each other by inheritance.

So when we talk about polymorphism, we are talking about the relationship between a base class and its derived classes. For example, in C#, we can have a base class (which would be the dog in this example) and then we can have multiple derived classes (poodle, bulldog), which all inherit the features (methods) of the base class but polymorphism allows  the poodle and bulldog to have their own unique implementation of the features (methods). By this we mean the derived class can also override some of the features of the base class. For example, a poodle might not Bark the same as a bulldog so we can override the Bark method in the derived class to make it unique to the poodle i.e the Bark method will perform different instructions when the base class is a poodle. 

This is what we mean by polymorphism, an object(Dog) can be of many forms (i.e. types) like a poodle or bulldog, but still, have the same features (e.g bark). So you can write code that can work with any object, regardless of its specific type.  

**Polymorphism in action**
Let's take a look at an example of polymorphism in action. We're going to create a base class called Dog, and then we'll create two derived classes – Poodle and Bulldog. The Dog class will have one method called Bark, and the Poodle and Bulldog classes will each have their own unique implementation of this method. Here's what our code will look like:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4u4mjighlas4cj7xdr1m.png)
This is an example of polymorphism in action – the Bark method is being "polymorphic" because it can be used in many different ways, depending on the object that it's being called on. 

**What is upcasting?**
When we talk about polymorphism, we often talk about "upcasting" and "downcasting". Upcasting is a type of polymorphism that allows us to convert a child class object into a parent class object. Upcasting is useful because it allows us to treat a child class object as if it were a parent class object, which can be handy in some situations such as when we need to pass a derived class object into a method that only accepts Base class objects
For example, let's say we have a method that takes a Dog as a parameter:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8q836y9qpkqfmxogqga3.png)
If we try to call this method with a Poodle, it won't work:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ia4n8cvvtzcw7qiwlcox.png)

This won't work because the DoSomething method is expecting a Dog, and we're trying to give it a Poodle. But if we upcast the Poodle to a Dog, it will work:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c7zms53o05yikeb8qbcf.png)

In this example, we've upcast the poodle to a Dog, and then passed it into the DoSomething method. This works because the DoSomething method is expecting a Dog, and we're giving it a Dog but it can implement the methods in the Poodle class. 
Upcasting is safe because a Poodle is always a Dog. But downcasting is not always safe, and we'll talk about why in the next section.

**What is downcasting?**
Downcasting is when we take a base class, and treat it as if it were a derived class. So in our example above, we could downcast a Dog to a Poodle:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2hnmcc3r8ozyhwc6e3jh.png)

 In this example, we've created a new Dog object and then downcast it to a Poodle. We can then call the Bark method on the Poodle object, and it will use the implementation in the Dog class. 
Downcasting is useful because it allows us to treat a base class as if it were a derived class. This can be helpful when we want to write code that can work with multiple types of objects. For example, let's say we have a method that takes a Poodle as a parameter:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/63ilgqro8va8ndzivbpk.png)

If we try to call this method with a Dog, it won't work:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dtq1js77o5chu5pp703e.png)

This won't work because the DoSomething method is expecting a Poodle, and we're trying to give it a Dog. 
But if we downcast the Dog to a Poodle, it will work:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wmt3lyf9mmy1rfee1ehg.png)

In this example, we've downcast the Dog to a Poodle, and then passed it into the DoSomething method. This works because the DoSomething method is expecting a Poodle, and we're giving it a Poodle.
Downcasting is not always safe because a Dog is not always a Poodle. So if we try to downcast a Dog to a Poodle, and the Dog is not actually a Poodle, we'll get an error:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7nenq2lvsiaipw0n6udt.png)

This code will throw an exception because the Dog is not actually a Poodle. 
So when should you downcast? You should only downcast when you're sure that the object is actually of the type that you're trying to downcast too. 

**What are the advantages of polymorphism?**
One benefit of using polymorphism is that it allows you to write code that is more flexible and extensible. For example, let's say you have a base class (e.g Dog) and a subclass (Poodle and Bulldog). If you later decide to add another subclass (e.g Cocker Spaniel), you can do so without having to change any of the existing code. This is because all of the subclasses will implement the same interface as the base class.
Another benefit of using polymorphism is that it can improve the performance of your codebase. This is because you, you can easily reuse the code that you wrote for the first subclass.
Another benefit of using polymorphism is that it makes development easier on large-scale projects. As we mentioned before, polymorphism allows you to reuse code more easily and avoid duplication. This is especially important on large-scale projects, where code duplication can lead to a lot of wasted time and effort.

Polymorphism is a complex concept and can be challenging to learn but understanding it is important for any C# programmer. I am a student who is learning polymorphism as part of object-orientated programming (OOP)  and I thought it might be useful to share what I have learned so far in a blog post. I hope you find it helpful! Please feel free to leave any comments below.