Extension functions and inheritance

There is a big difference between member functions and extension functions when we talk about inheritance.

The open class Canine has a subclass, Dog. A standalone function, printSpeak, receives a parameter of type Canine and prints the content of the result of the function speak(): String:

open class Canine {
open fun speak() = "<generic canine noise>"
}

class Dog : Canine() {
override fun speak() = "woof!!"
}

fun printSpeak(canine: Canine) {
println(canine.speak())
}

We already covered this in Chapter 1, Kotlin – Data Types, Objects and Classes, in the Inheritance section. Open classes with open methods (member functions) can be extended and alter their behavior. Invoking the speak function will act differently depending on which type is your instance.

The printSpeak function can be invoked with any instance of a class that is-a Canine, either Canine itself or any subclass:

printSpeak(Canine())
printSpeak(Dog())

If we execute this code, we can see this on the console:

Although both are Canine, the behavior of speak is different in both cases, as the subclass overrides the parent implementation.

But with extension functions, many things are different.

As with the previous example, Feline is an open class extended by the Cat class. But speak is now an extension function:

open class Feline

fun Feline.speak() = "<generic feline noise>"

class Cat : Feline()

fun Cat.speak() = "meow!!"

fun printSpeak(feline: Feline) {
println(feline.speak())
}

Extension functions don't need to be marked as override, because we aren't overriding anything:

printSpeak(Feline())
printSpeak(Cat()

If we execute this code, we can see this on the console:

In this case, both invocations produce the same result. Although in the beginning it seems confusing, once you analyse what is happening, it becomes clear. We're invoking the Feline.speak() function twice; this is because each parameter that we pass is a Feline to the printSpeak(Feline) function:

open class Primate(val name: String)

fun Primate.speak() = "$name: <generic primate noise>"

open class GiantApe(name: String) : Primate(name)

fun GiantApe.speak() = "${this.name} :<scary 100db roar>"

fun
printSpeak(primate: Primate) {
println(primate.speak())
}

printSpeak(Primate("Koko"))
printSpeak(GiantApe("Kong"))

If we execute this code, we can see this on the console:

 

In this case, it is still the same behavior as with the previous examples, but using the right value for name. Speaking of which, we can reference name with name and this.name; both are valid.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.205.99