codingstuff.io
ExploreTutorialsProblemsCS Subjects
Get Started
ExploreTutorialsProblemsCS Subjects
Get Started
codingstuff.io

Master the art of building software through interactive tutorials, real-world problems, and guided projects.

Pune, Maharashtra, India

codingstuffmail@gmail.com

Product

  • Explore
  • Tutorials
  • Problems
  • CS Subjects

Company

  • About
  • Contact
  • Privacy Policy
  • Terms & Conditions
  • Sitemap

© 2026 codingstuff.io. All rights reserved.

Built with ❤️ for developers everywhere

/
/
All Tutorials
🎯

Kotlin

22 / 68 topics
11Extensions Functions12Classes and Objects13Inheritance in Kotlin14Interfaces in Kotlin15Data Classes16Sealed Classes17Companion Objects18Generics in Kotlin19Type Aliases20Properties and Fields21Lateinit Properties22Delegated Properties
Tutorials/Kotlin/Delegated Properties
🎯Kotlin

Delegated Properties

Updated 2026-04-20
3 min read

Delegated Properties

Delegated properties are a powerful feature in Kotlin that allow you to delegate the implementation of property accessors (getters and setters) to another object. This can help reduce boilerplate code, make your code more readable, and promote reusability. In this section, we'll explore how delegated properties work, their use cases, and best practices for using them in your Kotlin applications.

What Are Delegated Properties?

A delegated property is a property whose getter and/or setter are implemented by another object. This other object is called the delegate. When you access or modify a delegated property, the corresponding method of the delegate is invoked.

Syntax

The syntax for declaring a delegated property in Kotlin is as follows:

var <property-name>: <type> by <delegate>
  • <property-name>: The name of the property.
  • <type>: The type of the property.
  • by: The keyword that indicates delegation.
  • <delegate>: The object that will handle the property access.

Example

Let's start with a simple example to illustrate how delegated properties work:

import kotlin.properties.Delegates

class User {
    var name: String by Delegates.observable("John") { _, oldValue, newValue ->
        println("Name changed from $oldValue to $newValue")
    }
}

fun main() {
    val user = User()
    user.name = "Jane"  // Output: Name changed from John to Jane
}

In this example, the name property is delegated to an observable delegate provided by Kotlin's standard library. The lambda expression passed to observable is called whenever the value of name changes.

Built-in Delegates

Kotlin provides several built-in delegates that you can use out of the box:

1. Delegates.observable

The observable delegate allows you to observe changes to a property and execute custom logic when the property's value changes.

import kotlin.properties.Delegates

class Counter {
    var count: Int by Delegates.observable(0) { _, oldValue, newValue ->
        println("Count changed from $oldValue to $newValue")
    }
}

fun main() {
    val counter = Counter()
    counter.count = 1  // Output: Count changed from 0 to 1
    counter.count = 2  // Output: Count changed from 1 to 2
}

2. Delegates.vetoable

The vetoable delegate allows you to veto changes to a property by returning true or false in the lambda expression.

import kotlin.properties.Delegates

class User {
    var age: Int by Delegates.vetoable(18) { _, oldValue, newValue ->
        if (newValue < 0) {
            println("Age cannot be negative")
            false
        } else {
            true
        }
    }
}

fun main() {
    val user = User()
    user.age = -5  // Output: Age cannot be negative
    println(user.age)  // Output: 18
}

3. Delegates.notNull

The notNull delegate ensures that a property is initialized before it's accessed.

import kotlin.properties.Delegates

class User {
    var name: String by Delegates.notNull()
}

fun main() {
    val user = User()
    // user.name = "John"  // Uncomment this line to initialize the property
    println(user.name)  // Throws IllegalStateException if not initialized
}

4. Delegates.lazy

The lazy delegate delays the initialization of a property until it's accessed for the first time.

import kotlin.properties.Delegates

class User {
    val name: String by Delegates.lazy {
        println("Initializing name")
        "John"
    }
}

fun main() {
    val user = User()
    println(user.name)  // Output: Initializing name, then John
    println(user.name)  // Output: John (no reinitialization)
}

Custom Delegates

You can also create your own custom delegates by implementing the ReadWriteProperty interface. This allows you to define how a property should be accessed and modified.

Example of a Custom Delegate

Let's create a custom delegate that logs every access to a property:

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

class LoggingDelegate<T>(private var value: T) : ReadWriteProperty<Any?, T> {
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        println("Accessing ${property.name}: $value")
        return value
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        println("Setting ${property.name} to $value")
        this.value = value
    }
}

class User {
    var name: String by LoggingDelegate("John")
}

fun main() {
    val user = User()
    println(user.name)  // Output: Accessing name: John, then John
    user.name = "Jane"  // Output: Setting name to Jane
    println(user.name)  // Output: Accessing name: Jane, then Jane
}

In this example, the LoggingDelegate class implements the ReadWriteProperty interface and logs every access and modification of the property.

Use Cases for Delegated Properties

1. Lazy Initialization

Delegated properties are particularly useful for lazy initialization, where a resource is expensive to create or initialize.

import kotlin.properties.Delegates

class DatabaseConnection {
    val connection: Connection by Delegates.lazy {
        println("Connecting to database")
        // Create and return the database connection
    }
}

fun main() {
    val db = DatabaseConnection()
    println(db.connection)  // Output: Connecting to database, then [connection object]
}

2. Property Validation

You can use delegated properties to enforce validation rules on property values.

import kotlin.properties.Delegates

class User {
    var age: Int by Delegates.vetoable(18) { _, oldValue, newValue ->
        if (newValue < 0 || newValue > 120) {
            println("Invalid age")
            false
        } else {
            true
        }
    }
}

fun main() {
    val user = User()
    user.age = -5  // Output: Invalid age
    println(user.age)  // Output: 18
}

3. Observable Properties

Delegated properties can be used to create observable properties that notify listeners of changes.

import kotlin.properties.Delegates

class User {
    var name: String by Delegates.observable("John") { _, oldValue, newValue ->
        println("Name changed from $oldValue to $newValue")
    }
}

fun main() {
    val user = User()
    user.name = "Jane"  // Output: Name changed from John to Jane
}

Best Practices

  1. Use Built-in Delegates When Possible: Kotlin provides several built-in delegates that cover common use cases. Using these can make your code more concise and easier to understand.

  2. Keep Delegates Simple: Custom delegates should be simple and focused on a single responsibility. Avoid overcomplicating the logic within a delegate.

  3. Document Delegates Clearly: If you create custom delegates, ensure that their behavior is well-documented. This will help other developers understand how they work and when to use them.

  4. Avoid Overuse: While delegated properties can be powerful, they should not be overused. Only use them when they provide a clear benefit in terms of code readability or reusability.

  5. Test Delegates Thoroughly: Since delegates encapsulate the behavior of property accessors, it's important to test them thoroughly to ensure that they work as expected.

Conclusion

Delegated properties are a powerful feature in Kotlin that can help you write cleaner and more maintainable code. By delegating the implementation of property accessors to another object, you can reduce boilerplate code, promote reusability, and make your code more readable. Whether you're using built-in delegates or creating custom ones, understanding how delegated properties work will enable you to write more efficient and effective Kotlin applications.


PreviousLateinit PropertiesNext Coroutines Basics

Recommended Gear

Lateinit PropertiesCoroutines Basics