๐ŸŽ“ A1Learner
๐Ÿ”
0 of 37 lessons completed

Kotlin Property Delegation

Property delegation hands the read and write work of a property to another object. The property keeps its name while the delegate does the work behind it.

A lazy value built once

The lazy block prints its line when the value is first read. The second read reuses the stored result, so the line prints only once.

class Heavy {
    val value: String by lazy {
        println("building once")
        "ready"
    }
}
fun main() {
    val heavy = Heavy()
    println(heavy.value)
    println(heavy.value)
}

An observable value that reports writes

Each write to level runs the callback with the old value and the new value. The middle write sets the same value again, and the callback still fires.

class Watched {
    var level: Int by kotlin.properties.Delegates.observable(0) { _, old, new ->
        println("level $old -> $new")
    }
}
fun main() {
    val watched = Watched()
    watched.level = 3
    watched.level = 3
    watched.level = 9
}

Properties read from a map

Each property reads its value from the map under its own name. The name property finds the Ana entry, and the age property finds the 30 entry.

class Person(val data: Map<String, Any?>) {
    val name: String by data
    val age: Int by data
}
fun main() {
    val person = Person(mapOf("name" to "Ana", "age" to 30))
    println(person.name)
    println(person.age)
}

Example

class Game {
    var score: Int by kotlin.properties.Delegates.observable(0) { _, old, new ->
        println("Score $old -> $new")
    }
    val badge: String by lazy {
        println("making badge")
        "Star player"
    }
}
fun main() {
    val game = Game()
    game.score = 10
    game.score = 25
    println(game.badge)
    println(game.badge)
}

Key points

  • The by keyword connects a property to its delegate.
  • A lazy delegate computes the value on the first read and then reuses that value.
  • An observable delegate runs a callback after each write to the property.
  • The observable callback fires even when the new value equals the old value.
  • The observable delegate sits in kotlin.properties.Delegates and is reached with its full name, with no import line.
  • A property can read its value from a map when the map is the delegate.

In this example, score uses an observable delegate, so each write prints the old and new values. The badge property uses a lazy delegate, so its block runs on the first read only. The second read of badge prints the stored text with no second making line.

Note

A map delegate looks the value up under the property name, so each key in the map must match a property name.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท Kotlin Playground

Exercise

A lazy property is read three times. How many times does its block run?