48. Property Delegation

A property can hand off its get/set logic to a delegate object with the by keyword. The standard library ships several ready-made delegates: lazy for deferred initialization, Delegates.observable for change notifications, and even a Map for dynamic lookups.

import kotlin.properties.Delegates

class Settings(map: Map<String, Any?>) {
    // Delegate properties to a map: lookups go through map["name"].
    val theme: String by map
    val fontSize: Int by map
}

fun main() {
    // lazy: the initializer runs once, on first access.
    val config: String by lazy {
        println("computing config...")
        "loaded"
    }
    println("before first access")
    println(config)   // triggers the initializer
    println(config)   // cached, no recompute

    // observable: a callback fires on every assignment.
    var status: String by Delegates.observable("idle") { _, old, new ->
        println("status: $old -> $new")
    }
    status = "running"
    status = "done"

    // delegating to a map.
    val settings = Settings(mapOf("theme" to "dark", "fontSize" to 14))
    println("${settings.theme}, ${settings.fontSize}")
}

Note the order in the output: "computing config..." appears only after "before first access" and prints just once, even though config is read twice — lazy computes on first access and caches the result.

Running it:

$ kotlin run
before first access
computing config...
loaded
loaded
status: idle -> running
status: running -> done
dark, 14
← Prev Index Next →