Polymorphism in Swift


In Swift, polymorphism is an essential feature of Object-Oriented Programming that allows objects of different classes to be treated as objects of a common superclass. It enables methods to perform differently based on the object calling them, even if they share the same interface.

Polymorphism in Swift is mainly achieved through method overriding and protocol conformance, allowing flexibility and dynamic method resolution at runtime. This helps in writing generic and reusable code.

Key Points to Remember

  • Polymorphism allows a single function, method, or operator to behave differently for different types of input.
  • It enables method overriding in subclasses to provide specific implementations of methods defined in the superclass.
  • Protocol-based polymorphism allows unrelated classes to share a common behavior by conforming to the same protocol.
  • Polymorphism supports dynamic dispatch, where the method that gets executed is determined at runtime based on the object type.
  • Helps achieve loose coupling and code reusability.

Syntax

class Superclass {
     func methodName() {
         // Superclass implementation
    }
}

class Subclass: Superclass {
     override func methodName() {
         // Subclass-specific implementation
    }
}

let object: Superclass = Subclass()
object.methodName()  // Calls overridden method in Subclass

Example 1: Method Overriding for Polymorphism

Let's demonstrate how method overriding allows polymorphic behavior in Swift.

import Foundation

class Shape {
     func area() {
         print("Calculating area of shape")
    }
}

class Circle: Shape {
     override func area() {
         print("Area of circle: πr²")
    }
}

class Rectangle: Shape {
     override func area() {
         print("Area of rectangle: length × width")
    }
}

let shapes: [Shape] = [Circle(), Rectangle()]

for shape in shapes {
    shape.area()
}

Output

Area of circle: πr²
Area of rectangle: length × width

Example 2: Polymorphism Using Protocols

Protocols enable polymorphism without inheritance by defining common behaviors for unrelated types.

import Foundation

protocol Drawable {
     func draw()
}

class Triangle: Drawable {
     func draw() {
         print("Drawing a triangle")
    }
}

class Square: Drawable {
     func draw() {
         print("Drawing a square")
    }
}

let drawables: [Drawable] = [Triangle(), Square()]

for drawable in drawables {
    drawable.draw()
}

Output

Drawing a triangle
Drawing a square

Example 3: Polymorphism with Class Hierarchies and Method Overriding

Here’s another example showing how polymorphism works with a real-world analogy of employees.

import Foundation

class Employee {
     func work() {
         print("Employee is working")
    }
}

class Manager: Employee {
     override func work() {
         print("Manager is managing the team")
    }
}

class Developer: Employee {
     override func work() {
         print("Developer is writing code")
    }
}

let employees: [Employee] = [Manager(), Developer(), Employee()]

for employee in employees {
    employee.work()
}

Output

Manager is managing the team
Developer is writing code
Employee is working

Example 4: Function Accepting Superclass Type Demonstrating Polymorphism

A function that takes a superclass type can accept any subclass object, showcasing polymorphism.

import Foundation

class Animal {
     func makeSound() {
         print("Some generic animal sound")
    }
}

class Cat: Animal {
     override func makeSound() {
         print("Meow")
    }
}

class Dog: Animal {
     override func makeSound() {
         print("Bark")
    }
}

func animalSound(animal: Animal) {
    animal.makeSound()
}

let myCat = Cat()
let myDog = Dog()

animalSound(animal: myCat)  // Output: Meow
animalSound(animal: myDog)  // Output: Bark

Output

Meow
Bark