Polymorphism

One Type, Many Forms

A variable of a parent type can hold any child object. When you call an overridden function, Kotlin runs the version of the actual object at runtime (dynamic dispatch). This lets you write code once for all subtypes.

Example

open class Notification(val to: String) {
    open fun send() = println("Sending notification to $to")
}

class SmsNotification(to: String) : Notification(to) {
    override fun send() = println("SMS to $to: Your OTP is 4821")
}

class EmailNotification(to: String) : Notification(to) {
    override fun send() = println("Email to $to: Order confirmed")
}

class PushNotification(to: String) : Notification(to) {
    override fun send() = println("Push to $to: Your food is on the way")
}

fun notifyAll(list: List<Notification>) {
    for (n in list) n.send()   // the right version is picked at runtime
}

fun main() {
    notifyAll(listOf(
        SmsNotification("+91 98xxxx1234"),
        EmailNotification("[email protected]"),
        PushNotification("device-77"),
    ))
}

Output

SMS to +91 98xxxx1234: Your OTP is 4821
Email to [email protected]: Order confirmed
Push to device-77: Your food is on the way

Overloading vs Overriding

OverloadingOverriding
Whatsame name, different parameterssame signature in a subclass
Decided atcompile timeruntime
Keywordnoneoverride (parent must be open)
Examplesum(a, b) and sum(a, b, c)send() in SmsNotification

Exercise

Exercise: Create an open class Vehicle with an open function fare(km: Int): Int returning km * 10. Override it in Auto (km * 15) and Bike (km * 7). Print the fare for 5 km for each vehicle in a list.

Show answer
open class Vehicle { open fun fare(km: Int) = km * 10 }
class Auto : Vehicle() { override fun fare(km: Int) = km * 15 }
class Bike : Vehicle() { override fun fare(km: Int) = km * 7 }

fun main() {
    listOf(Vehicle(), Auto(), Bike()).forEach { println(it.fare(5)) } // 50, 75, 35
}