Extend your code readability with Kotlin extensions

Kotlin Vocabulary: extension functions and properties

Meghan Mehta
Android Developers

--

Have you ever used an API and wanted to add functionality or a property to it?

You could inherit from the class or create a function that takes in an instance of the class to solve this problem. The Java programming language usually solves this problem with a Utils class but this does not show up in autocomplete which makes it harder to find and less intuitive to use. Both of these work as solutions but neither promote easy, readable code.

Thankfully, Kotlin comes to the rescue with extension functions and properties. These let you add functionality to a class without the need to inherit or create a function that takes in the class. Unlike the Java programming language’s equivalent, extensions appear in Android Studio’s autocomplete. Extensions can be used with third party libraries, Android SDK, or user defined classes.

Read on to find out how to extend your code readability with extensions!

Extension functions — usage

Let’s say that you have a class called Dog that has a name, breed and age.

An adoption agency may want to extend the Dog class to have a function that prints the dog’s information if someone is interested in adopting. To do this, we implement an extension function, which is set up like a normal function with one exception: you add in the class you are extending before your function name and a dot in between. In the function implementation you are able to use this to refer to the receiver object and you have access to all the members of the receiver class inside your function block.

You can call printDogInformation() just like you would call any other function in the Dog class.

Calling extension functions from Java code

Extension functions are not part of the class we’re extending, so when trying to call them from the Java programming language, we won’t find them among the other methods of that class. As we’ll see later, extensions decompile into static methods of the file you defined them in and receive as parameter an instance of the class we’re extending. This is what it would look like to call the printDogInformation() extension from Java.

Extension functions on nullable types

You can even use extensions on nullable types. Instead of doing null checks before calling the extension function, we can create the extension function on the nullable type and make the null check part of the function implementation. This is what the printInformation() looks like using nullable types.

As you can see, you do not need to null check before calling printInformation().

Extension properties — usage

Adoption agencies may also want to know if a dog is old enough to be adopted. To do this, we implement an extension property called isReadyToAdopt which checks that the dog is older than 1 year.

You can call this extension property the same way you would call any other property in the Dog class.

Extension function overriding

You cannot override an existing member function. If you define an extension function with the same signature as an already existing member function, the member function will always be called because the function that’s called depends on the declared static type of the variable, not on the runtime type of the value stored in that variable. For example, you can’t extend toUppercase() on String, but you can extend convertToUppercase().

The consequence of this behavior is shown when you extend a type you don’t own and the library owners add a method to their library with the same signature as your extension. In this case the library extension will be called. The only information you’ll get is that your extension function becomes an unused method.

Under the hood

We can take the printDogInformation() and decompile it in Android Studio by going to Tools/Kotlin/Show Kotlin Bytecode then press the Decompile button. If we look at the printDogInformation() method as decompiled code we get this:

Under the hood, extension functions are just regular static functions that take in an instance of the receiver class. They do not have any other connection to the receiver classes. This is why there are no backing fields — they do not actually insert members into the class.

Conclusion

Overall, extensions are a useful tool to be used thoughtfully, remember the tips below when you use them to make your code more intuitive and readable.

Remember:

  • Extensions are resolved statically.
  • Member functions will always win.
  • Adopt a dog!

Happy coding!

--

--