[TUT] Kotlin Extension Functions by Example

Kotlin Extension functions allow you to add behaviour (think methods/functions) to any other type on the platform or in your codebase. The idea being to allow for greater flexibility and less boiler plate code.

Let’s have a quick run through of how to create them and what are some advantages and disadvantages.

The official docs:

Kotlin, similar to C# and Gosu, provides the ability to extend a class with new functionality without having to inherit from the class or use any type of design pattern such as Decorator. This is done via special declarations called extensions. Kotlin supports extension functions and extension properties.

To create an extension function, in a new file you declare a function. The difference being you prepend the function name with the class that you want to extend.

For example, here is an extension function on String that will replace all spaces with underscores.

fun String.spaceToUnderscore(): String = this.replace(" ", "_")

Side note, that the above is taking advantage of Kotlin’s one line methods. And could be written in long hand like so:

fun String.underscore(): String {
    return this.replace(" ", "_")
}

As you can imagine, that is a quite niche extension function. However it is quite powerful if you have a programme that just doesn’t like spaces, because calling the code like this, is much clearer.

// Without extension function
val newString = "Hello World".replace(" ", "_")
// With extension function
val newString = "Hello World".spaceToUnderscore()

Extension functions become much more powerful when you combine them with other libraries, say for instance, there is a Speech to Text library that requires you to pass your speech (voice input) in a custom format, normally you would have to make a Util or some type of conversion function, or even create a decorator to make this happen.

Now you can create one extension function, and call that method on each of the 3rd party API objects. Allowing for a much more fluid interface.

By the same stroke, the disadvantage of Kotlin extension functions, is that they hide some of the complexity, or its not so much that they hide it. It’s that they allow you to put code anywhere to change anything.

Here is a example of an extension function, that I would argue is deceitful and not clean code at all. The below extension function extends String to allow it to be converted to a file, then to a ByteArray and then finally to a 3rd party object.

fun String.byteString(): ByteString = ByteString.copyFrom(File(this).readBytes())

Why is this so bad? In itself it looks like a quite handy method, but when you come to use it:

val byteString = "/my/file/location/file.zip".byteString()

It’s not obvious to the caller that this is actually referencing the zip file at the location, getting that File and getting the byteString from that (vs getting the ByteString of the String itself). This is something to be careful about and not to use extension functions “just because you can”.

Remember: When you have a hammer, everything looks like a nail

To recap, kotlin extension functions are powerful and encourage easier to read code. Ensure though that you are not confusing or hiding important details.

To create an extension function you declare a function. The difference being you prepend the function name with the class that you want to extend.

fun Blog.end(): String = this.finish()