
Delegation is a design pattern that allows an object to delegate tasks to a helper instance. Kotlin provides the language level support for the delegation pattern by introducing a keyword by.
The syntax is: val/var <property name>: <Type> by <expression>
var name: String
by
DelegateClass()
The expression after the keyword by , satisfies the convention for property delegates.
Kotlin Standard Delegates
Kotlin’s standard library provides several implementations of the delegated properties.
Lazy
lazy will be very useful when implementing read-only properties that perform that want to delay the initialization until it is accessed for the first time. The code in lambda executes only when we refer to this property.
val lazyValue: String by lazy { println("Initialization!") "Hello" } fun main() { println(lazyValue) println(lazyValue) }
Output
Initialization! Hello Hello
As per the above output, the lambda passed to the lazy function was executed only once.
Observable
This delegate is useful for when an action must be done each time a property’s value changes.
It takes two arguments: The initial value of the property and a callback that’s called after the property is assigned a new value.
var observableValue: String by Delegates.observable(“Initial Value") { property, old, new -> println("${property.name}: $old -> $new") } fun main() { observableValue = “New Data" observableValue = “Another Data" }
Output
observableValue: Initial Value -> New Data observableValue: New Data -> Another Data
NotNull
We can use notNull delegate to prevent the usage of nullable type and refer to the field without safe call operator. It works similar to lateinit in that it will throw an IllegalStateException if a property is accessed before it is initialized.
var name by notNull<String>() fun main() { println(name) // java.lang.IllegalStateException: Property name should be initialized before get name = “Abi” println(name) // Abi }
Writing Custom Delegate
We can write our custom delegates, rather than using ones that already exist. This relies on writing a class that extends one of two interfaces that Kotlin provides.
interface ReadOnlyProperty<in R, out T> { operator fun getValue(thisRef: R, property: KProperty<*>): T } interface ReadWriteProperty<in R, T> { operator fun getValue(thisRef: R, property: KProperty<*>): T operator fun setValue(thisRef: R, property: KProperty<*>, value: T) }
For a read-only property (val), a delegate has to provide an operator function getValue() with the following parameters:
- thisRef – Reference of the property is in
- property – A reflection description of the property being delegated
For a mutable property (var), a delegate has to additionally provide an operator function setValue() with the following parameters:
- thisRef – Reference of the property is in
- property – A reflection description of the property being delegated
- value – The new value of the property
Let’s consider an example to get user details for which all the details should be trimmed.
We can do this by using the custom setter, it will be called every time we assign a value to the property.
var name: String set(value) { field = value.trim() } fun main() { name = “Jack " println(name) }
Output
Jack
Well, we have achieved this for user’s name property. If we want to trim the user’s address, city and state then we have to keep the custom setter for all the property as like below.
var address: String set(value) { field = value.trim() } var city: String set(value) { field = value.trim() } var state: String set(value) { field = value.trim() }
There are lot of boilerplate code and we can solve this with Property Delegation.
class TrimDelegate : ReadWriteProperty<Any, String> { private var trimString = "" override fun getValue(thisRef: Any, property: KProperty<*>) = trimString override fun setValue(thisRef: Any, property: KProperty<*>, value: String) { trimString = value.trim() } }
We have created our Trim Delegate class. We can use it for property whose value should be trimmed.
var name by TrimDelegate() var address by TrimDelegate() var city by TrimDelegate() var state by TrimDelegate()
Kotlin Delegate properties help the developer to write reusable and clean code. Hope I have given you a basic idea on this and we shall connect in some other interesting blogs.
– Prakash B,
Android Development Team,
Mallow Technologies.