Kotlin extensions

Discover How To Use Kotlin Extensions

In this article we’ll show you how to use Kotlin extensions to enhance some classes with custom functionality in your project. You will learn how this feature can improve the reusability, readability and flexibility in your code very easily.

Kotlin extensions allow us to enhance classes out of our control, for example classes imported from a library or even from the JDK. We could make use of this to avoid repetitive code and embed our code into the class by using extensions.

Let’s see how!

Discover How To Use Kotlin Extensions » The Bored Dev
Photo by Bruno Bueno: @Pexels

Extension functions

To declare a Kotlin extension function you will have to declare a function in the same way you normally do, with the only difference that you will have to add a prefix to your function name including the “receiver” type. We call receiver type to the class “receiving” the enhancement.

To be able to understand extensions easily, we’re going to go through a small Kotlin extension function example. Let’s assume we have the following Customer class with its corresponding CustomerType.

data class Customer(val name: String, val type: CustomerType, val countryCode: String)

enum class CustomerType {
    BASIC,
    PREMIUM
}

Let’s say that we now have a hypothetical requirement to show premium customers for a given country. Let’s write a test for that.

    @Test
    fun `should filter premium customers from a given country`() {

        val customers = listOf(
            Customer("John Smith", BASIC, "GB"),
            Customer("Vincenzo Panucci", PREMIUM, "IT"),
            Customer("Enzo Bertolucci", BASIC, "IT"),
            Customer("Antonio Miranda", PREMIUM, "ES"),
            Customer("Ralf Meier", PREMIUM, "GB"),
        )

        val results = customers.filter { c -> c.type == PREMIUM && c.countryCode == "IT" }

        assertThat(results).containsExactly(Customer("Vincenzo Panucci", PREMIUM, "IT"))
    }

We’re populating an initial list of basic and premium customers for different countries, we then filter them to get only the premium customers from Italy (IT).

Now let’s assume that we need to filter premium users from a given country in multiple places in our codebase, what would be the best way to address this? The answer is in Kotlin extensions!

We’re going to create an extension to be able to filter a List<Customer> type easily. Our extension would look like this:

    fun List<Customer>.premiumFor(country: String): List<Customer> {
        return this.filter { c -> c.type == PREMIUM && c.countryCode == country }
    }

We’re declaring List<Customer> as the receiver and then we declare a premiumFor(country: String) function for that receiver type. As simple as that!

Having declared this extension function we can now change our test to use this extension.

    @Test
    fun `should filter premium customers from a given country using an extension function`() {

        val customers = listOf(
            Customer("John Smith", BASIC, "GB"),
            Customer("Vincenzo Panucci", PREMIUM, "IT"),
            Customer("Enzo Bertolucci", BASIC, "IT"),
            Customer("Antonio Miranda", PREMIUM, "ES"),
            Customer("Ralf Meier", PREMIUM, "GB"),
        )

        val results = customers.premiumFor("IT")

        assertThat(results).containsExactly(Customer("Vincenzo Panucci", PREMIUM, "IT"))
    }

You can notice that our code becomes more reusable and concise now. We can use this extension anywhere in our code, not having to rewrite our lambda every time. The best thing is that the new function seems to belong to the receiver interface now from a user’s perspective, something that comes in very handy.

Scope

Another thing to keep in mind with extensions is the scope where they will be available.

When you declare an extension it will be available within the scope of the package where it has been defined. Generally we should define extensions at the root of the package level where we’d like the extension to be available.

For example, let’s say that we define our extension under this package:

package com.theboreddev.customer

fun List<Customer>.premiumFor(countryCode: String): List<Customer> {
    return this.filter { c -> c.type == CustomerType.PREMIUM && c.countryCode == "IT" }
}

If we wanted to use this extension from package com.theboreddev.billing, we will have to import the extension as it was any static method in the way we used to in Java. Let’s create a new test class from this package:

package com.theboreddev.billing

import com.theboreddev.Customer
import com.theboreddev.CustomerType
import com.theboreddev.premiumFor
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test

class ExtensionScopeTest {

    @Test
    fun `should filter premium customers from a given country using an extension function`() {

        val customers = listOf(
            Customer("John Smith", CustomerType.BASIC, "GB"),
            Customer("Vincenzo Panucci", CustomerType.PREMIUM, "IT"),
            Customer("Enzo Bertolucci", CustomerType.BASIC, "IT"),
            Customer("Antonio Miranda", CustomerType.PREMIUM, "ES"),
            Customer("Ralf Meier", CustomerType.PREMIUM, "GB"),
        )

        val results = customers.premiumFor("IT")

        Assertions.assertThat(results).containsExactly(Customer("Vincenzo Panucci", CustomerType.PREMIUM, "IT"))
    }
}

Notice how we are now under com.theboreddev.billing, in order to be able to use the extension we have to add the import import com.theboreddev.premiumFor shown above.

Conclusion

Extensions are a very powerful feature provided by Kotlin, in our personal opinion is probably one of the biggest advantages above Java right now. It improves reusability and readability enormously, taking an extra step in terms of flexibility for the software developer.

Once you start using them you will see how useful they are and how they allow customising your code very easily.

If you’re interested in reading more articles about Kotlin, you can check all of our Kotlin articles here.

That’s all from us today! We hope you’ve learned something today and looking forward to seeing you again very soon!

As always, if you like our articles, follow us to be notified when new content gets published! Thanks!