Kotlin Explained: Property delegation
Modularize your codebase the smart way
The delegation, in general, is a design pattern allowing to extract the control over a specific element to an external component. In this article, we are going to explore how to make use of Kotlin built-in language support for the delegation in order to implement our custom delegated properties. Let’s get started with the basics first 🚀.
Property vs Field
To understand the concept of property delegation let’s start with taking a look at the actual difference between the property and the field. Let’s consider the following Java and Kotlin code snippets:
- A simple Java class
Acontaining a property called name:
- And a similar Kotlin class:
As you can see, in Kotlin we can declare a property in a similar way as we do for the Java field. However, those code snippets are in fact two different concepts. So, what’s the actual difference? Let’s take a look at what an equal Java implementation of the Kotlin class
A.kt would look like:
- Java class
Awith getter and setter functions:
- Matching Kotlin implementation:
By default, under the hood, each mutable class property in Kotlin has a backing JVM field generated along with getter and setter functions. However, those exist only in the corresponding JVM bytecode generated for the Kotlin class and are not visible in the Kotlin code explicitly.
In the case of an immutable property, only the field and getter function is generated, as follows:
- Java implementation of class A containing an immutable property:
- Matching Kotlin implementation:
However, often we are overriding the default implementation of the getter and setter functions whenever we want them to perform an additional preprocessing of the parameter or field value. Let’s consider the following example:
The User class☝️consists of the two properties —
val name: String and
val surname: String. Both of them have custom getter function implementations. Note that those
get() functions implementations in fact both perform the same logic.
At this point, we can ask a question: Is this code clean? 🤔
For sure it’s not 😅, because of the code duplication in the
get() functions. And this is a case where the language built-in property delegation pattern can help us remove the duplicate implementation.
How can we refactor this code to make both getters reusable? The answer is — with the property delegation. Let’s see how we can delegate the getter functions implementation to an external, reusable class and integrate it into the
- Let’s create a new class called
NameDelegatewhich is going to take over the control over our properties.
2. Declare an internal property of NameDelegate class responsible for storing the value in a backing class field:
3. Move the implementation of the
User.surname properties’ getters to the
Now we can use the
NameDelegate class to delegate the properties to its instances. Let’s see how to do it in action:
That’s it, super simple! Kotlin allows delegating a property to an external object with using the by keyword. Under the hood, when the delegated property is read the
NameDelegate.getValue() function is invoked. Also, whenever the new value is set to the property the
NameDelegate.setValue() function is being called. This is what the
by keyword instructs the compiler to arrange.
The delegated property can act the same way as a normal property would. It has its own type specified which limits its capabilities. Let’s see how it works in action:
As a result, the piece of code above would produce the following output to the console 👀:
User name: Sam, surname: O’hey.
Kotlin built-in support for delegation using dedicated
by keyword provides us a perfect way to modularize our codebase in a clean way. We should definitely use it whenever you need to avoid duplicating the code of your properties accessor functions. It is also a good practice to delegate the properties in order to extract any additional business logic out of the entity class scope in order to keep them simple.
Delegation support in Kotlin makes it possible to approach other programming problems in a smart and clean way. It can be also used to implement different types of design patterns with reduced boilerplate code overhead. Delegated properties combined with extension functions are also invaluable when it comes to Android apps development and allow to reduce a lot of boilerplate code responsible for platform-specific operations.
The next articles of the Kotlin Explained series, are going to focus on the other Kotlin language and standard library features and concepts which makes the daily programming useful. You can expect also more articles with hands-on examples of using property delegates available in the standard library which are super useful and provide ready to use design patterns out-of-the-box. I’m also going to write more in detail on how we can apply delegation on the Android to modularize the codebase efficiently and reduce the boilerplate code especially when it comes to dealing with Bundle, SharedPreferences, memory leaks and more.
Are interested in learning more about applying Kotlin delegation to more advanced problems and use cases? Stay tuned! If there is something specific you’d like to learn about just let me know in the comment.
If you’ve found this article useful please show it your love by clicking some claps 👏 on the left-hand side 👈. This way you can let me know my work is important for you. It motivates to write more. Thanks!