Kotlin Vocabulary: Delegates
One way to get some work done is to delegate that work to another party. No, I am not talking about delegating your work to your friend, but delegating work from one object to another.
Guess what, delegation is not new to software. Delegation is a design pattern in which an object handles a request by delegating to a helper object, called the delegate. The delegate is responsible for handling the request on behalf of the original object and making the results available to the original object.
Kotlin makes delegation easier by providing support for class and property delegates and even containing some built-in delegates of its own.
Let’s say you have a use case for an
ArrayList that can recover its last removed item. Basically, all you need is the same
ArrayList functionality with a reference to the last removed item.
One way to do this is to extend the
ArrayList class. Since this new class is extending the concrete
ArrayList rather than implementing the
MutableList interface, it is highly coupled with the concrete
Wouldn’t be nice if you could override the
remove() function to keep a reference of the deleted item and delegate the rest of the empty implementations of
MutableList to some other object. Kotlin provides a way to achieve this by delegating most of the work to an internal
ArrayList instance and customizing its behavior. To do this, Kotlin introduces a new keyword:
Let’s see how class delegation works. When you use the
by keyword, Kotlin automatically generates the code to use the
innerList instance as a delegate.
by keyword tells Kotlin to delegate functionality from the
MutableList interface to an internal
ArrayList instance named innerList.
ListWithTrash still supports all the functions in the
MutableList interface by providing direct bridge methods to the internal
ArrayList object. Plus, now you have the ability to add your own behavior.
Under the hood
Let’s see how this works. If you take a look at the decompiled Java code from the
ListWithTrash byte code, you’ll see that Kotlin compiler actually creates wrapper functions that call corresponding functions on the internal
Note: The Kotlin compiler uses another design pattern called the Decorator Pattern to support class delegation in the generated code. In the decorator pattern, the decorator class shares the same interface with the class to be decorated. The decorator class keeps an internal reference of the target class and wraps, or decorates, all the public methods provided with the interface.
Delegates are especially useful when you can’t inherit from a particular class. With class delegation, your class is not part of any class hierarchy. Instead, it shares the same interface and decorates the internal object of the original type. This means you can easily switch the implementation without breaking the public API.
Besides class delegation, you can also use the
by keyword to delegate properties. With property delegation, the delegate is responsible for handling calls to the
set functions of the property. This can be extremely useful if you need to reuse the getter/setter logic across other objects and lets you easily extend functionality beyond simple backing fields.
Let’s imagine you have a
Person class that is defined like this:
class Person(var name: String, var lastname: String)
name property of this class has some formatting requirements. When the
name is set, you want to make sure the first letter is capitalized while formatting the rest in lowercase. Also, when updating the name, you want to automatically increment the update count property.
You could implement this functionality as shown here:
While this works, what if the requirements change and you want to increment
updateCount each time the
lastname changes, too? You could copy/paste the logic to write a custom setter, but suddenly you’d find yourself writing the same exact setter for each property:
Both setter methods are almost identical, telling you one of them shouldn’t exist. With property delegation, we can reuse code by delegating getters and setters to a property.
Just like class delegation, you can use
by to delegate a property, and Kotlin will generate the code to use the delegate when you use property syntax.
With this change, you’ve delegated the
lastname properties to the
FormatDelegate class. Now let’s take a look at the code for
FormatDelegate. The delegate class needs to implement
ReadProperty<Any?, String> if you need to delegate only the getter, or
ReadWriteProperty<Any?, String> if you need to delegate both the getter and the setter. In our case,
FormatDelegate needs to implement
ReadWriteProperty<Any?, String> since you want to perform the formatting when the setter is invoked.
You may have noticed there are two additional parameters in the getter and the setter functions. The first parameter is
thisRef and represents the object that contains the property.
thisRef can be used for accessing the object itself for purposes such as checking other properties or calling other class functions. The second parameter is
KProperty<*>, which can be used for accessing metadata on the delegated property.
Looking back at the requirement, let’s use
thisRef to access and increment the
Under the hood
To understand how this works, let’s take a look at the decompiled Java code. The Kotlin compiler generates both the code to keep private references of the
FormatDelegate object for
lastname properties along with getters/setters that contain the logic you’ve added.
The compiler also creates a
KProperty to store the delegated properties. If you take a look at the generated getters and setters for the
name property, the instance is stored at index 0 while the
lastname property is stored at index 1.
With this trick, any caller can access the delegated property with regular property syntax.
person.lastname = “Smith” // calls generated setter, increments count
println(“Update count is $person.count”)
Kotlin not only supports delegates but also provides built-in delegates in the Kotlin Standard Library, which we’ll see in more detail in another article.
Delegates can help you delegate tasks to other objects and provide better code reuse. The Kotlin compiler creates the code to let you use delegates seamlessly. Kotlin uses simple syntax with the
by keyword to delegate a property or a class. Under the hood, the Kotlin compiler generates all the necessary code to support delegation without exposing any change to the public API. Simply put, Kotlin generates and maintains all the needed boilerplate code for delegates, or in other words, you can delegate your delegates to Kotlin.