Explain how delegation works in Kotlin.
sobes.tech AI
Answer from AI
Delegation in Kotlin is a mechanism that allows an object to delegate some of its responsibilities to another object. This is implemented without inheritance, which promotes more flexible composition.
It is used for:
- Reusing functionality.
- Implementing the Delegation pattern.
Kotlin supports delegation at the class level and property level.
At the class level:
A class can delegate the implementation of an interface to another object using the by operator. This eliminates the need to manually override all interface methods.
// Interface
interface Base {
fun printMessage()
fun printMessageLine()
}
// Delegate class
class BaseImpl(val x: Int) : Base {
override fun printMessage() {
print(x)
}
override fun printMessageLine() {
println(x)
}
}
// Class delegating implementation
class Derived(b: Base) : Base by b
At the property level:
The value of a property can be computed through a delegate. This allows implementing patterns such as lazy initialization, observable properties, and properties with thread-local storage.
Syntax: val <propertyName>: <PropertyType> by <delegateExpression>.
Examples of built-in property delegates:
lazy: For lazy initialization. The value is computed only upon the first access.val lazyValue: String by lazy { println("Computing lazyValue") "Hello" } fun main() { println(lazyValue) // "Computing lazyValue" will be printed here println(lazyValue) // Second call will not recompute }Delegates.observable: Calls a specified block of code when the property value changes.import kotlin.properties.Delegates var name: String by Delegates.observable("<no name>") { prop, old, new -> println("$old -> $new") } fun main() { name = "Alice" // <no name> -> Alice name = "Bob" // Alice -> Bob }Delegates.vetoable: Allows canceling the assignment of a new value if a condition is not met.import kotlin.properties.Delegates var max: Int by Delegates.vetoable(0) { prop, old, new -> new > old } fun main() { println(max) // 0 max = 10 println(max) // 10 max = 5 // Will not change because 5 ≤ 10 println(max) // 10 }
Creating custom property delegates:
Implemented by the interfaces ReadOnlyProperty or ReadWriteProperty.
ReadOnlyProperty: Forvalproperties. ImplementsgetValue.ReadWriteProperty: Forvarproperties. ImplementsgetValueandsetValue.
import kotlin.reflect.KProperty
class ExampleDelegate {
var value: String = "Initial value"
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
println("$thisRef, thank you for delegating '${property.name}' to me!")
return value
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$thisRef, thank you for notifying about assigning '${property.name}' to new value '$value'")
this.value = value
}
}
class Container {
var myProp: String by ExampleDelegate()
}
fun main() {
val c = Container()
println(c.myProp) // Accesses getValue
c.myProp = "New value" // Accesses setValue
println(c.myProp)
}
Delegation ensures code cleanliness, improves readability, and promotes the DRY (Don't Repeat Yourself) principle.