ZetCode

Kotlin by Keyword

last modified April 19, 2025

Kotlin's delegation pattern is implemented using the by keyword. It allows composition over inheritance and property delegation. This tutorial explores the by keyword in depth with practical examples.

Basic Definitions

The by keyword in Kotlin enables delegation. It has two main uses: class delegation and property delegation. Class delegation lets you implement interfaces by delegating to another object. Property delegation delegates property access to another object.

Class Delegation

Class delegation allows implementing an interface by delegating to another object. This is useful for the decorator pattern without boilerplate code.

ClassDelegation.kt
package com.zetcode

interface SoundMaker {
    fun makeSound()
}

class Dog : SoundMaker {
    override fun makeSound() = println("Woof!")
}

class LoudAnimal(private val animal: SoundMaker) : SoundMaker by animal {
    fun makeLoudSound() {
        println("!!!")
        makeSound()
        println("!!!")
    }
}

fun main() {
    val loudDog = LoudAnimal(Dog())
    loudDog.makeLoudSound()
}

Here LoudAnimal implements SoundMaker by delegating to the provided animal. The by keyword handles all interface method calls. We add new functionality without modifying the original class.

Property Delegation Basics

Property delegation delegates getter/setter calls to another object. The delegate must implement getValue and optionally setValue.

PropertyDelegation.kt
package com.zetcode

import kotlin.reflect.KProperty

class SimpleDelegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "Delegate for '${property.name}'"
    }
}

class Example {
    val message by SimpleDelegate()
}

fun main() {
    val example = Example()
    println(example.message) // Output: Delegate for 'message'
}

The SimpleDelegate provides the value for message. The by keyword connects the property to its delegate. The delegate's getValue is called when accessing the property.

Lazy Initialization

The lazy delegate initializes properties only when first accessed. This is useful for expensive initialization that might not be needed.

LazyDelegate.kt
package com.zetcode

class HeavyObject {
    init {
        println("Heavy object created")
    }
}

class Container {
    val heavy by lazy { HeavyObject() }
}

fun main() {
    val container = Container()
    println("Container created")
    container.heavy // Initialization happens here
}

The heavy property is initialized only when first accessed. The output shows "Container created" before "Heavy object created". This demonstrates lazy initialization.

Observable Properties

The Delegates.observable delegate allows observing property changes. It calls a handler whenever the property value changes.

ObservableDelegate.kt
package com.zetcode

import kotlin.properties.Delegates

class User {
    var name: String by Delegates.observable("<no name>") {
        prop, old, new ->
        println("$old -> $new")
    }
}

fun main() {
    val user = User()
    user.name = "John" // Output: <no name> -> John
    user.name = "Jane" // Output: John -> Jane
}

Each time name changes, the handler prints the old and new values. The by keyword connects the property to the observable delegate. This is useful for change tracking.

Vetoable Properties

The Delegates.vetoable delegate allows rejecting property changes. The handler can return false to veto the change.

VetoableDelegate.kt
package com.zetcode

import kotlin.properties.Delegates

class PositiveNumber {
    var value: Int by Delegates.vetoable(0) { _, old, new ->
        new >= 0
    }
}

fun main() {
    val num = PositiveNumber()
    num.value = 42
    println(num.value) // Output: 42
    
    num.value = -1
    println(num.value) // Output: 42 (change rejected)
}

The delegate only accepts non-negative numbers. The attempt to set -1 is rejected, keeping the previous value. The by keyword enables this validation behavior.

Custom Property Delegate

You can create custom delegates by implementing the property operator functions. This allows complete control over property access.

CustomDelegate.kt
package com.zetcode

import kotlin.reflect.KProperty

class RangeDelegate(
    private val min: Int,
    private val max: Int,
    private var value: Int
) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
        return value
    }
    
    operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: Int) {
        if (newValue in min..max) {
            value = newValue
        }
    }
}

class Config {
    var setting by RangeDelegate(0, 100, 50)
}

fun main() {
    val config = Config()
    println(config.setting) // Output: 50
    
    config.setting = 75
    println(config.setting) // Output: 75
    
    config.setting = 150
    println(config.setting) // Output: 75 (unchanged)
}

The RangeDelegate restricts values to a specified range. The by keyword connects the property to our custom delegate. Invalid values are silently ignored, keeping the previous valid value.

Map Delegation

Properties can be delegated to a map, with property names as keys. This is useful for dynamic property access and JSON-like structures.

MapDelegate.kt
package com.zetcode

class User(val map: Map<String, Any?>) {
    val name: String by map
    val age: Int by map
}

fun main() {
    val user = User(mapOf(
        "name" to "John Doe",
        "age" to 30
    ))
    
    println("${user.name}, ${user.age}") // Output: John Doe, 30
}

The User class delegates properties to values in the provided map. The by keyword connects each property to its corresponding map entry. This pattern is often used with JSON deserialization.

Best Practices for Delegation

Source

Kotlin Delegation Documentation

This tutorial covered Kotlin's by keyword in depth, showing both class and property delegation patterns. We explored standard delegates and created custom ones. Delegation is a powerful tool for code reuse and separation of concerns in Kotlin.

Author

My name is Jan Bodnar, and I am a passionate programmer with many years of programming experience. I have been writing programming articles since 2007. So far, I have written over 1400 articles and 8 e-books. I have over eight years of experience in teaching programming.

List all Kotlin tutorials.