Photo by Sohum Raninga on Unsplash

Extension functions

Extension functions provide an instant way to enrich a class functionality without accessing its source code:

fun String.beginChar() : Char = this.get(0)

In this example, we are creating a new method in the java.lang.String class that returns the first character of the stored text.

Extensions are a powerful mechanism that may come in handy in several scenarios. For instance, if we want to improve the several classes in our project used for utilities (a.k.a. the infamous “XXXUtils.java” files).

Object Oriented Programming

On the other hand, Kotlin can be used to apply some common O.O.P. principles, like polymorphism. So we can add specific behavior for child classes when creating a class hierarchy:

abstract class Geometry(val w : Int = 0, val h : Int = 0) { abstract fun area()}

class Rectangle(w : Int, h : Int) : Geometry(w, h) {
     override fun area() = println(" w * h       -> $w * $h = ${w * h}")
}

class Triangle(w : Int, h : Int) : Geometry(w, h) {
     override fun area() = println("(w * h) / 2  -> $w * $h / 2 = ${w * h/2}")
} 

If we check the output for these classes looping inside a collection that contains different instances…

val figures : List<Geometry> = 
   listOf(Rectangle(1, 2), Triangle(3, 4), Rectangle(5, 6))

for (figure in figures) {
     figure.area()
}

… we get the expected result. Although the list is declared to contain “Geometry” objects (left-side of the assignment), the given objects for its initialization (right-side) prevail because method calls are binded during execution. As a result, we get the tailor-made behavior for each subclass.

“Class methods are resolved dinamically”

Now the question would be: can we combine both principles? Is it possible to apply polymorphism when declaring extension functions? Let’s give it a try step by step.

Overriding extension functions

First of all, we declare some extension functions in a “geometryExtensions.kt” file:

fun Geometry.dump() = println("Dumping here all GEOMETRY contents…")

After that, we override the extension function in both subclasses:

fun Rectangle.dump() = println("Dumping here all RECTANGLE contents…")

fun Triangle.dump() = println("Dumping here all TRIANGLE contents…")

Finally, we loop again to check the outputs:

val figures : List<Geometry> = 
   listOf(Rectangle(1, 2), Triangle(3, 4), Rectangle(5, 6))

for (figure in figures) {
    figure.dump()
}

As you can see, there’s something wrong… All the time we get the message from the superclass implementation.

Why? Extensions functions are compiled down to static methods that receive instances of the extended class as parameters. These methods are included in Java classes that use the file name as the created class name. So, in the previous example, we are generating something similar to:

// Auto-generated class created from geometryExtensions.kt
public class GeometryExtensionsKt {
     public static void dump(Geometry geo) {
     //XXX: code here....
     }

     public static void dump(Rectangle rec) {
    //XXX: code here
    }

    public static void dump(Triangle tri) {
    //XXX: code here
    }
}

And the usage of these classes is resolved in a static way. So it doesn’t matter the specific type of objects we put in our array, because we will always get the behavior for the class given in the declaration (left-side of assignment.

“Extensions are resolved statically, so polymorphism won’t work”

Wrapping up

Extension functions and method overriding are powerful features, but in this scenario they can’t be combined. As a recap, keep in mind the main difference between instance methods and extensions the next time you code a class hierarchy: dynamic vs static resolution.

You can find the source code in the following link from kotlin playground:

https://pl.kotl.in/BJvoEbtWL

Join the Conversation

3 Comments

Leave a comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: