Understanding Polymorphism in Swift: A Comprehensive Guide

ElAmir Mansour
4 min readDec 23, 2023

--

Polymorphism → Many Forms

Polymorphism, a cornerstone of object-oriented programming, empowers developers to write flexible and reusable code. In the realm of Swift, this concept takes center stage, offering a myriad of tools such as inheritance, protocols, and generics. In this article, we’ll embark on a savory exploration of polymorphism using a delectable analogy: burgers.

Example: The Burger Hierarchy

Consider a class hierarchy where Burger is the parent class, and various burger types are represented by subclasses. Each burger type inherits core attributes from the parent class but adds its unique twist.

class Burger {
var name: String
var patty: String
var toppings: [String]

init(name: String, patty: String, toppings: [String]) {
self.name = name
self.patty = patty
self.toppings = toppings
}

func describe() {
print("A \(name) with \(patty) patty and toppings: \(toppings.joined(separator: ", "))")
}
}

class Cheeseburger: Burger {
var cheeseType: String

init(name: String, patty: String, toppings: [String], cheeseType: String) {
self.cheeseType = cheeseType
super.init(name: name, patty: patty, toppings: toppings)
}

// Overriding the describe method
override func describe() {
print("A \(name) with \(patty) patty, toppings: \(toppings.joined(separator: ", ")), and \(cheeseType) cheese.")
}
}

class VeggieBurger: Burger {
var veggiePatty: String

init(name: String, toppings: [String], veggiePatty: String) {
self.veggiePatty = veggiePatty
super.init(name: name, patty: "Veggie", toppings: toppings)
}

// Overriding the describe method
override func describe() {
print("A \(name) with Veggie patty, toppings: \(toppings.joined(separator: ", "))")
}
}

In this example, Burger is the generic parent class, while Cheeseburger and VeggieBurger are specialized subclasses. Each subclass inherits the core properties of a burger but introduces additional features.

Let’s instantiate and use these burger classes to witness polymorphism in action.

// Creating instances of different burger types
let classicBurger = Burger(name: "Classic Burger", patty: "Beef", toppings: ["Lettuce", "Tomato", "Onion"])
let cheesyDelight = Cheeseburger(name: "Cheesy Delight", patty: "Beef", toppings: ["Bacon", "Pickles"], cheeseType: "Cheddar")
let veggieDelight = VeggieBurger(name: "Veggie Delight", toppings: ["Avocado", "Sprouts"], veggiePatty: "Black Bean")

// Using polymorphism: Storing different burger types in an array
let allBurgers: [Burger] = [classicBurger, cheesyDelight, veggieDelight]

// Iterating through the array and invoking the describe method
for burger in allBurgers {
burger.describe()
}

In the above code, the array allBurgers contains instances of different burger types, demonstrating the beauty of polymorphism. The describe method is called on each burger, and thanks to dynamic dispatch, the overridden describe methods in the subclasses are invoked, showcasing the unique characteristics of each burger type.

Example : The Animal Kingdom

Consider a hierarchy where Animal serves as the base class, and various animal types are represented by subclasses. Each animal exhibits unique characteristics, and through polymorphism, we can encapsulate their shared behaviors.

class Animal {
var name: String
var sound: String

init(name: String, sound: String) {
self.name = name
self.sound = sound
}

func makeSound() {
print("\(name) says: \(sound)")
}
}

class Lion: Animal {
override init(name: String) {
super.init(name: name, sound: "Roar")
}

// Additional lion-specific methods or properties can be added here
}

class Penguin: Animal {
override init(name: String) {
super.init(name: name, sound: "Honk")
}

// Additional penguin-specific methods or properties can be added here
}

class Elephant: Animal {
override init(name: String) {
super.init(name: name, sound: "Trumpet")
}

// Additional elephant-specific methods or properties can be added here
}

In this example, Animal is the generic superclass, and Lion, Penguin, and Elephant are specialized subclasses. Each subclass inherits the common properties and behaviors from Animal but introduces its unique characteristics.

Now, let’s create instances of these animals and observe the magic of polymorphism in action:

// Creating instances of different animals
let simba = Lion(name: "Simba")
let skipper = Penguin(name: "Skipper")
let dumbo = Elephant(name: "Dumbo")

// Using polymorphism: Storing different animals in an array
let zoo: [Animal] = [simba, skipper, dumbo]

// Iterating through the array and invoking the makeSound method
for animal in zoo {
animal.makeSound()
}

In this code snippet, the array zoo contains instances of different animals. Through polymorphism, we can treat all these animals uniformly, calling the makeSound method on each one. Thanks to dynamic dispatch, the overridden makeSound methods in the subclasses are invoked, showcasing the distinct sounds of lions, penguins, and elephants.

“Those were some examples to let you understand what polymorphism is “

If you found this blog helpful or have any questions, feel free to reach out to me on social media:

I look forward to connecting with you and exploring more about Enums in Swift together! Thanks for reading.

--

--

ElAmir Mansour
ElAmir Mansour

Written by ElAmir Mansour

🚀 Software Engineer & iOS Developer | Scrum Master 🕹 | Crafting Code & Content | Coffee enthusiast ☕️ | Simplifying Complexity, One Line at a Time 💻

No responses yet