# Polymorphism

Course: [Dart](https://www.devtutorials.ai/learn/dart) · Section: Object-Oriented Programming
Source: https://www.devtutorials.ai/learn/dart/object-oriented/polymorphism

> How abstract classes and interfaces set out what a class must do, and how polymorphism lets one call run a different method for each kind of object.

## What Are Abstract Classes and Interfaces?

- **Abstract class** = a class that is only a **plan**. You cannot make objects from it directly.
- **Abstract method** = a method with **no body**. It is a promise: "every child will write this".
- **Interface** = a **contract**: a list of members that a class promises to have.
- In Dart, **every class is also an interface**. You sign it with `implements`.

**Simple lesson:** an abstract class says **what** must be done, and the child classes say **how**.

### A Real-World Example

The school canteen takes payment in three ways: cash, card and UPI.

- Every way must be able to **pay** an amount.
- But each way pays **differently**: count notes, swipe, or scan a QR code.
- So the canteen writes one plan, `Payment`, with a `pay()` promise.
- Each payment type fills in its own `pay()`.

Every **Run** box on this page runs on the course's Dart runner in your browser.

This lesson builds on **Inheritance**. Make sure `extends`, `@override` and `super` feel familiar first.

## What You Will Learn

In this lesson, you will learn:

1. Abstract classes and abstract methods.
2. Interfaces, `implements`, and using several at once.
3. When to use `extends` and when to use `implements`.
4. How a parent-type variable can hold a child object.
5. How Dart picks the right method while the program runs.

## Abstract Classes

### The abstract Keyword

```text
abstract class Name {
  ReturnType method();        // abstract: no body
  ReturnType other() => ...;  // concrete: has a body
}
```

- **Concrete class** = a normal class. You can make objects of it.
- **Abstract class** = a class marked `abstract`. You **cannot** make objects of it.

```dart runnable expect-error title="You cannot make an object of a plan"
abstract class Shape {
  double area();
}

void main() {
  var s = Shape();
  print(s);
}
```

Dart stops this before running. A `Shape` with no real `area()` would be useless.

### Abstract Methods

An abstract method ends with `;` instead of a body. Every concrete child **must** give it a body:

```dart runnable title="Each shape fills in area()"
abstract class Shape {
  String get name;
  double area();
}

class Circle extends Shape {
  final double r;
  Circle(this.r);

  @override
  String get name => 'Circle';

  @override
  double area() => 3.14 * r * r;
}

class Rectangle extends Shape {
  final double w, h;
  Rectangle(this.w, this.h);

  @override
  String get name => 'Rectangle';

  @override
  double area() => w * h;
}

void main() {
  var shapes = [Circle(1.5), Rectangle(2.5, 4.2)];
  for (var s in shapes) {
    print('${s.name}: ${s.area().toStringAsFixed(2)}');
  }
}
```

### Forgetting a Promise

Try ticking and unticking the members below. The class only compiles when every promise is kept:

```dart runnable expect-error title="The child forgot area()"
abstract class Shape {
  double area();
}

class Square extends Shape {
  final double side;
  Square(this.side);
}

void main() {
  print(Square(2.5).side);
}
```

The error lists the missing member: `Shape.area`.

**Simple lesson:** an abstract method is a promise, and Dart checks that every concrete child keeps it.

## Concrete Members in Abstract Classes

An abstract class can **also** have normal fields, constructors and methods. Children inherit them as usual.

```dart runnable title="A plan with some work already done"
abstract class Payment {
  final int amount;
  Payment(this.amount);

  void pay();

  void receipt() {
    print('Paid Rs. $amount');
    print('Thank you!');
  }
}

class Cash extends Payment {
  Cash(super.amount);

  @override
  void pay() => print('Counting notes for Rs. $amount');
}

class Upi extends Payment {
  final String id;
  Upi(super.amount, this.id);

  @override
  void pay() => print('Sending Rs. $amount to $id');
}

void main() {
  var list = [Cash(40), Upi(65, 'canteen@gvs')];
  for (var p in list) {
    p.pay();
    p.receipt();
  }
}
```

- `pay()` is different for each child, so it is abstract.
- `receipt()` is the same for all, so it is written **once** in the parent.

**Simple lesson:** put the shared work in the abstract class, and leave only the different parts abstract.

## Interfaces

### Implicit Interfaces

**Implicit interface** = in Dart, every class **automatically** defines an interface: the list of all its public members.

- There is no `interface` keyword needed. Any class works as one.
- `class B implements A` means "B promises to have **every** member of A".
- With `implements`, B inherits **no code**. It must write **every** member itself.

```dart runnable title="Implementing a normal class"
class Speaker {
  void speak() => print('...');
}

class Robot implements Speaker {
  @override
  void speak() => print('Beep. I am a robot.');
}

void main() {
  Speaker s = Robot();
  s.speak();
  print(s is Speaker);
}
```

### Multiple Interfaces

A class can extend **one** parent, but implement **many** interfaces:

```dart runnable title="A smart board is three things at once"
abstract class Display {
  void show(String text);
}

abstract class Speaker {
  void say(String text);
}

abstract class Charger {
  int get watts;
}

class SmartBoard implements Display, Speaker, Charger {
  @override
  void show(String text) => print('[screen] $text');

  @override
  void say(String text) => print('[speaker] $text');

  @override
  int get watts => 65;
}

void main() {
  var board = SmartBoard();
  board.show('Good morning, Class 7A');
  board.say('Good morning, Class 7A');
  print('Charges at ${board.watts} W');
  print(board is Display && board is Charger);
}
```

An **`abstract class` with only abstract members** is how you write a "pure" interface in Dart.

Name it after what it can do: `Printable`, `Payable`, `Speaker`.

**Simple lesson:** `implements` signs a contract. You get no code, only the promise to write every member.

## extends or implements?

| | `extends` | `implements` |
|---|---|---|
| How many? | **one** parent | **many** interfaces |
| Gets code? | **yes**, all public members | **no**, write everything |
| Must override? | only abstract members | **every** member |
| `super` works? | yes | no |
| Means | "is a kind of" | "can do the job of" |

### When to Use Each

- **`extends`** when the child really **is a** kind of parent, and you want to **reuse** its code.
- **`implements`** when unrelated classes must **work the same way**, but share no code.
- **Abstract class** when you have a plan with some shared work, plus some parts each child must fill in.

```dart runnable title="Both together"
abstract class Printable {
  void printMe();
}

class Person {
  final String name;
  Person(this.name);
}

class Student extends Person implements Printable {
  final int marks;
  Student(super.name, this.marks);

  @override
  void printMe() => print('$name scored $marks');
}

class Notice implements Printable {
  final String text;
  Notice(this.text);

  @override
  void printMe() => print('NOTICE: $text');
}

void main() {
  List<Printable> pile = [Student('Asha', 92), Notice('Sports Day on Friday')];
  for (var p in pile) {
    p.printMe();
  }
}
```

A `Student` and a `Notice` have nothing in common, except that both can be printed.

**Easy way to remember**

- **abstract class** = a plan. No objects. Some methods have no body.
- **implements** = sign a contract. Get no code. Write every member.
- **extends** = join a family. Get the code. Override only what you need.

**Simple lesson:** use `extends` to share code, and `implements` to share a promise.

## What Is Polymorphism?

**Polymorphism** = "many forms". **One** line of code works with **many** kinds of objects, and each object does it **its own way**.

- You call the same method name: `s.area()`.
- A circle works out a circle's area. A square works out a square's area.
- You do not need an `if` for every kind of shape.

**Simple lesson:** polymorphism means "same call, different behaviour, chosen by the object".

### A Real-World Example

At morning assembly, the principal says one sentence: "**Everyone, show your ID.**"

- A student shows a student card.
- A teacher shows a staff card.
- A visitor shows a visitor pass.
- The principal does not ask each person what they are. Each person knows what to do.

Press the button and watch which `area()` runs for each shape:

The rest of this lesson uses **Inheritance** and the abstract classes from above.

## Parent-Type References

### A Parent Variable, a Child Object

A variable of the **parent** type can hold any **child** object:

```dart runnable title="Animal a = Dog()"
class Animal {
  void speak() => print('Some sound');
}

class Dog extends Animal {
  @override
  void speak() => print('Woof');
}

class Cow extends Animal {
  @override
  void speak() => print('Moo');
}

void main() {
  Animal a = Dog();
  a.speak();
  a = Cow();
  a.speak();
}
```

- The variable's type is `Animal`.
- The **object** inside it is a `Dog`, then a `Cow`.
- Each time, the object's own `speak()` runs.

### What the Variable Type Allows

The **variable's type** decides which methods you **may call**. The **object** decides which version **runs**.

```dart
class Dog extends Animal {
  void fetch() => print('Fetching!');
}

Animal a = Dog();
a.fetch();   // Error: The method 'fetch' isn't defined for the class 'Animal'.
```

- Not every `Animal` can fetch, so Dart refuses.
- To use `fetch()`, check the type first: `if (a is Dog) a.fetch();`

```dart runnable title="Check with is, then use the child's method"
class Animal {
  void speak() => print('Some sound');
}

class Dog extends Animal {
  @override
  void speak() => print('Woof');
  void fetch() => print('Fetching the ball!');
}

void main() {
  Animal a = Dog();
  a.speak();
  if (a is Dog) {
    a.fetch();
  }
}
```

After `a is Dog` is `true`, Dart **promotes** `a` to a `Dog` inside the `if`. (You saw type promotion in **Null Safety**.)

**Simple lesson:** the variable's type says what you may call, and the object says what actually runs.

## Runtime Method Resolution

**Runtime method resolution** = Dart picks **which** version of a method to run **while the program runs**, by looking at the real object.

- The line `p.speak()` never changed.
- What ran changed, because the object changed.

**Simple lesson:** Dart looks at the object, not the variable, to decide which method runs.

## Polymorphism Through Abstract Classes

An abstract class is the most common way. It promises the method, and every child fills it in:

```dart runnable title="Every payment pays in its own way"
abstract class Payment {
  void pay(int rupees);
}

class Cash implements Payment {
  @override
  void pay(int rupees) => print('Cash: Rs. $rupees counted');
}

class Card implements Payment {
  @override
  void pay(int rupees) => print('Card: Rs. $rupees swiped');
}

class Upi implements Payment {
  @override
  void pay(int rupees) => print('UPI: Rs. $rupees sent');
}

void checkout(Payment method, int bill) {
  print('Bill is Rs. $bill');
  method.pay(bill);
}

void main() {
  checkout(Upi(), 85);
  checkout(Cash(), 40);
}
```

- `checkout` takes **any** `Payment`. It never asks which kind.
- Tomorrow you can add `Wallet implements Payment`. `checkout` needs **no change**.

This is the big win: **new kinds** of objects can be added **without** changing the code that uses them.

Code that works on the parent type keeps working for every child, even ones written later.

**Simple lesson:** write functions for the parent type, and every child will fit.

## Polymorphism Through Interfaces

Classes that are **not related** can still be used the same way, if they implement the same interface:

```dart runnable title="Things that can make a sound"
abstract class Noisy {
  String sound();
}

class SchoolBell implements Noisy {
  @override
  String sound() => 'Ring ring!';
}

class Whistle implements Noisy {
  @override
  String sound() => 'Phweet!';
}

class Parrot implements Noisy {
  @override
  String sound() => 'Hello, teacher!';
}

void main() {
  List<Noisy> noisy = [SchoolBell(), Whistle(), Parrot()];
  for (var n in noisy) {
    print('${n.runtimeType}: ${n.sound()}');
  }
}
```

A bell, a whistle and a parrot have no common parent. The `Noisy` interface is enough.

**Simple lesson:** an interface lets unrelated classes stand in the same line.

## Practical Example: Shapes

```dart runnable title="Total area of a drawing"
abstract class Shape {
  String get name;
  double area();
}

class Circle extends Shape {
  final double r;
  Circle(this.r);
  @override
  String get name => 'Circle';
  @override
  double area() => 3.14 * r * r;
}

class Square extends Shape {
  final double side;
  Square(this.side);
  @override
  String get name => 'Square';
  @override
  double area() => side * side;
}

class Triangle extends Shape {
  final double base, height;
  Triangle(this.base, this.height);
  @override
  String get name => 'Triangle';
  @override
  double area() => 0.5 * base * height;
}

void main() {
  List<Shape> drawing = [Circle(2.5), Square(3.5), Triangle(4.5, 5.5)];
  var total = 0.0;
  for (var s in drawing) {
    print('${s.name}: ${s.area().toStringAsFixed(2)}');
    total += s.area();
  }
  print('Total area: ${total.toStringAsFixed(2)}');
}
```

Avoid long `if (s is Circle) ... else if (s is Square) ...` chains to pick a formula.

That is a sign the formula should be a method on each class. Then one call, `s.area()`, does the job.

**Easy way to remember**

- **Variable type** = what you are allowed to ask.
- **Object** = who answers, and how.
- One call, many answers: that is **polymorphism**.

**Simple lesson:** give each class its own version of the method, and let one loop call them all.

## TL;DR

1. **`abstract class`** is a plan. Abstract methods have no body, and every concrete child must write them.
2. **Every class is an interface.** `implements A, B` promises every member, and gives no code.
3. **`extends`** reuses code. **`implements`** shares a promise.
4. **Polymorphism:** `Shape s = Circle();` One call, a different method for each object.
5. The variable type says what you may call. The object decides what runs.

## Common mistakes

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| `var s = Shape();` for an abstract class | Abstract classes make objects | Make objects of a concrete child | A compile error: it is abstract. |
| Forgetting to write an abstract method | It has a default | Every concrete child must write it | A "missing implementations" error. |
| Expecting code from `implements` | `implements` is like `extends` | `implements` gives no code at all | Every member must be written again. |
| Calling `super.x()` after `implements` | `super` reaches the interface | `super` only reaches the `extends` parent | A compile error. |
| `abstract void pay();` | Methods need the `abstract` word | Only the class gets `abstract` | A compile error. |
| One giant interface | More members is better | Keep interfaces small and focused | Classes must write members they never use. |
| `Animal a = Dog(); a.fetch();` | The object is a Dog, so it works | The variable type limits the calls | A compile error. Check `a is Dog` first. |
| Long `is` chains to choose behaviour | `if` is clearer | Put the behaviour in a method on each class | Every new class means editing the chain. |
| Thinking the parent's method runs | `Animal a` means Animal's version | The object's version runs | Surprise output. |
| Forgetting `@override` | The name is enough | `@override` catches typos | A typo makes a new method, and the parent's runs instead. |
| `List<Dog>` for mixed animals | Any list fits | Use the parent type: `List<Animal>` | A Cat cannot be added. |

## Check Yourself

## Exercises

## What to Remember

- An abstract class is a plan that children fill in.
- `implements` signs a contract, and you write every member yourself.
- A parent-type variable or list can hold any child object.
- Dart picks the method from the real object while the program runs.
- Prefer a method on each class over a long chain of `is` checks.

Next: **Mixins**. You will add ready-made abilities to classes, and new methods to types like String.
