Kotlin Tutorial · Advanced Kotlin · Lesson 25 of 31

Kotlin Delegation: by lazy and Delegated Properties

Delegate interface implementations with by, and properties with lazy, observable and map-backed delegates.

Create a free account to save this page, take notes and track your progress. Sign in

Class delegation

class X(inner: Interface) : Interface by inner forwards every interface method to inner; you override only what you want to change. It's composition without boilerplate.

Class delegation with by
interface Repository {
    fun find(id: Int): String?
    fun count(): Int
}

class MemoryRepository : Repository {
    private val data = mapOf(1 to "Ana", 2 to "Ben")
    override fun find(id: Int) = data[id]
    override fun count() = data.size
}

class LoggingRepository(private val inner: Repository) : Repository by inner {
    override fun find(id: Int): String? {
        println("find($id)")
        return inner.find(id)
    }
}

fun main() {
    val repo = LoggingRepository(MemoryRepository())
    println(repo.find(2))
    println(repo.count())                 // forwarded without logging
}

Output

find(2)
Ben
2

Run this on your computer — see “Get Started” for setup.

Delegated properties

  • by lazy { } computes the value on first access and caches it (thread-safe by default).
  • Delegates.observable runs a callback on every change.
  • A property can be read from a Map (val name: String by map).
lazy, observable and map delegates
import kotlin.properties.Delegates

class Settings(values: Map<String, Any?>) {
    val theme: String by values
    val fontSize: Int by values

    val expensive: String by lazy {
        println("computing...")
        "ready"
    }

    var status: String by Delegates.observable("idle") { _, old, new ->
        println("status: $old -> $new")
    }
}

fun main() {
    val s = Settings(mapOf("theme" to "dark", "fontSize" to 14))
    println("${s.theme} ${s.fontSize}")
    println(s.expensive)
    println(s.expensive)                  // cached: no second "computing..."
    s.status = "saving"
    s.status = "saved"
}

Output

dark 14
computing...
ready
ready
status: idle -> saving
status: saving -> saved

Run this on your computer — see “Get Started” for setup.

Test yourself

When is a by lazy property's initializer run?

  1. When the object is created
  2. On first access, and the result is cached
  3. Every time it's read
  4. At compile time
Show answer

Answer: On first access, and the result is cached

Was this page helpful?