# Polymorphism — Compile-Time vs Runtime, Overloading vs Overriding

Source: https://skills101.in/learn/oops/oop-polymorphism — Skills101 free tutorial (OOP Concepts). Updated 2026-11-09.

**Polymorphism** ("many forms") means the **same call** behaves differently depending on the object. It's what lets you add new types without changing existing code.

![One call, shape.area(), gives π·r² for a Circle, a² for a Square and ½·b·h for a Triangle](https://skills101.in/learn-img/oops/polymorphism.svg)

## 1. Runtime polymorphism (overriding)

A child class **overrides** a parent method. Code that uses the parent type automatically runs the right child version — decided **at runtime** (dynamic dispatch).

```java
abstract class Shape {
    abstract double area();
}
class Circle extends Shape {
    double r;
    Circle(double r) { this.r = r; }
    double area() { return Math.PI * r * r; }
}
class Square extends Shape {
    double a;
    Square(double a) { this.a = a; }
    double area() { return a * a; }
}

public class Main {
    static double totalArea(Shape[] shapes) {     // works for ANY shape, even future ones
        double sum = 0;
        for (Shape s : shapes) sum += s.area();
        return sum;
    }
    public static void main(String[] args) {
        Shape[] shapes = { new Circle(1), new Square(2), new Square(3) };
        System.out.printf("%.3f%n", totalArea(shapes));
    }
}
```

```text
16.142
```

Add a `Triangle` class tomorrow and `totalArea` works unchanged. That's the **Open/Closed principle** in action.

## 2. Compile-time polymorphism (overloading)

Same method name, **different parameter lists** — the compiler picks one based on the arguments.

```java
public class Main {
    static String format(int amount) { return "₹" + amount; }
    static String format(double amount) { return String.format("₹%.2f", amount); }
    static String format(int amount, String currency) { return currency + " " + amount; }

    public static void main(String[] args) {
        System.out.println(format(500));
        System.out.println(format(99.5));
        System.out.println(format(20, "USD"));
    }
}
```

```text
₹500
₹99.50
USD 20
```

| | Overloading | Overriding |
|---|---|---|
| Also called | compile-time / static polymorphism | runtime / dynamic polymorphism |
| Where | same class | parent and child |
| Signature | **different** parameters | **same** parameters |
| Decided | by the compiler | by the object at runtime |

## 3. Python: duck typing

Python doesn't need a common parent. If an object has the method, you can call it — **"if it walks like a duck and quacks like a duck…"**

```python
class Upi:
    def pay(self, amt): return f"Paid {amt} by UPI"
class Card:
    def pay(self, amt): return f"Paid {amt} by card"
class Cash:
    def pay(self, amt): return f"Paid {amt} in cash"

for method in [Upi(), Card(), Cash()]:
    print(method.pay(499))
```

```text
Paid 499 by UPI
Paid 499 by card
Paid 499 in cash
```

Python has no method overloading by parameter types — use default arguments or `*args` instead.

## 4. Operator overloading

Classes can define what `+`, `==`, `<` mean for their objects.

```python
class Money:
    def __init__(self, rupees):
        self.rupees = rupees
    def __add__(self, other):
        return Money(self.rupees + other.rupees)
    def __eq__(self, other):
        return self.rupees == other.rupees
    def __repr__(self):
        return f"₹{self.rupees}"

print(Money(200) + Money(350), Money(5) == Money(5))
```

```text
₹550 True
```

(Java doesn't allow operator overloading for your own classes; C++ and Python do.)

## Common mistakes

- Thinking overloading is runtime polymorphism.
- Changing a parameter type when you meant to override — that creates an overload. Use `@Override` in Java to catch it.
- Writing `if type == "circle" … elif type == "square"` chains instead of using polymorphism.

## Quick recap

- Polymorphism: one call, different behaviour per object.
- Runtime = overriding + dynamic dispatch; compile time = overloading.
- Python uses duck typing; operator overloading with `__add__`, `__eq__`.
- It lets you add new types without changing existing code.


Practice quiz and free certificate: https://skills101.in/learn/oops/oop-polymorphism