Introduction
In software engineering, delegation is an object-oriented design pattern that allows an object to hand over certain responsibilities to another object. Instead of duplicating logic or relying heavily on inheritance, delegation promotes object composition and modular code reuse.
According to Wikipedia:
The delegation pattern is an object-oriented design pattern that allows object composition to achieve the same code reuse as inheritance.
In Kotlin, delegation is not just a pattern — it is built into the language as a first-class feature. This makes it simple and powerful to implement.
What Is Delegation?
- Delegation means outsourcing part of a class’s behavior to another object.
- It is often used when you want to reuse functionality from an existing class.
- The delegating class holds the delegate as an instance and forwards calls to it.
In Practice
- Inheritance: brings all behavior from the parent class.
- Delegation: selectively reuses some behavior from another class.
Types of Delegation in Kotlin
Kotlin supports two main forms of delegation:
1. Property Delegation
In property delegation, getter and setter logic of a property is handled by another object.
The syntax looks like this:
val/var <propertyName>: <Type> by <delegate>
Under the hood, the Kotlin compiler creates a hidden property (prop$delegate
) and routes all property access to the delegate.
Examples of Standard Delegates
Lazy Properties
val name: String by lazy {
println("Computed once!")
"Kotlin"
}
The lambda runs only the first time the property is accessed.
Observable Properties
import kotlin.properties.Delegates
var age: Int by Delegates.observable(0) { property, oldValue, newValue ->
println("${property.name} changed from $oldValue to $newValue")
}
Each assignment triggers a callback with metadata provided by KProperty
.
2. Class Delegation
Kotlin also allows entire interface implementations to be delegated.
interface Printer {
fun printMessage()
}
class SimplePrinter : Printer {
override fun printMessage() = println("Hello from Printer!")
}
class LoggingPrinter(printer: Printer) : Printer by printer
Here, LoggingPrinter
declares that it implements Printer
, but instead of re-implementing methods, it forwards calls to the given printer
instance.
Kotlin Properties
A property in Kotlin is more than just a field — it is a combination of:
- A backing field (variable)
- Accessor methods (getter/setter)
This unified model is what enables powerful property delegation features.
KProperty in Delegation
KProperty
is part of Kotlin’s reflection API, representing metadata about a property:
- Name, type, annotations
- Can be used to inspect or manipulate properties at runtime
- In delegation, it provides context to the delegate (e.g., the property name being accessed)
For example, in observable
, the property
parameter is a KProperty
instance.
Delegation vs Inheritance
Aspect | Inheritance | Delegation |
---|---|---|
Mechanism | Takes all behavior from parent | Reuses only part of another class |
Relationship | "Is-a" relationship | "Has-a" relationship |
Flexibility | Limited to one superclass | Combine multiple delegates |
Delegation promotes composition over inheritance, leading to cleaner, more modular systems.
Translation Rules for Delegated Properties
When you declare a delegated property, the Kotlin compiler:
- Generates an auxiliary hidden property (e.g.,
prop$delegate
). - Makes the original property’s getter/setter call into the delegate.
For example:
val name: String by lazy { "Kotlin" }
translates to something like:
private val name$delegate = lazy { "Kotlin" }
val name: String
get() = name$delegate.value
Should I Use a Function or a Property?
Kotlin encourages a semantic distinction:
- If it describes behavior → use a function
- e.g.
run()
,jump()
,walk()
- e.g.
- If it describes state → use a property
- e.g.
name
,lastName
,weight
- e.g.
More: Kotlin Academy Blog