Mallow's Blog

A short note on Property Delegation in Kotlin

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.

Leave a Reply

%d bloggers like this: