liveBook · Manning

Delegation

As explained in Kotlin in Action, 2E

Delegation is a composition pattern in which one object forwards operations or property lookup to another object that provides the behavior.

Delegation is a composition pattern: instead of performing an operation itself, an object forwards it to a helper object that supplies the behavior. In Kotlin, language support removes much of the forwarding code that a hand-written wrapper or decorator would otherwise require. section 9.5 section 4.3.3

For class delegation, a class implements the same interface as the wrapped object and keeps that object as a field. Methods whose behavior needs no change are forwarded; methods needing extra behavior can be overridden locally. Kotlin expresses the forwarding relationship with by and generates the routine interface implementations. section 4.3.3

Listing 4.29 Using class delegation
class CountingSet<T>(
    private val innerSet: MutableCollection<T> = hashSetOf<T>()
) : MutableCollection<T> by innerSet {                           #1
 
    var objectsAdded = 0
 
    override fun add(element: T): Boolean {                      #2
        objectsAdded++
        return innerSet.add(element)
    }
 
    override fun addAll(elements: Collection<T>): Boolean {      #2
        objectsAdded += elements.size
        return innerSet.addAll(elements)
    }
}
 
fun main() {
    val cset = CountingSet<Int>()
    cset.addAll(listOf(1, 1, 2))
    println("Added ${cset.objectsAdded} objects, ${cset.size} uniques.")
    // Added 3 objects, 2 uniques.
}

CountingSet delegates MutableCollection operations to innerSet, but overrides add and addAll to count attempted additions. The remaining collection behavior stays with the wrapped collection. section 4.3.3

This is useful when a wrapper should preserve most behavior while adding one focused responsibility. A counting collection can compare attempted additions with final size, helping measure a deduplication process without reimplementing the collection interface. section 4.3.3

Delegation also applies to properties. Rather than duplicating getter and setter logic, a property can send reads and writes to a delegate object. This supports properties whose values or access behavior are more complex than a backing field, including values associated with databases, browser sessions, or maps. section 9.5

Listing 9.23 Using delegated properties to make properties observable
class Person(val name: String, age: Int, salary: Int) : Observable() {
   var age by ObservableProperty(age, this)
   var salary by ObservableProperty(salary, this)
}

The age and salary properties delegate storage and change notification to ObservableProperty. Declaring each property with by replaces repeated accessor code while retaining observer notifications. section 9.5.3

A property delegate follows Kotlin conventions through operator getValue and setValue functions. The delegate can receive property metadata, allowing an observable implementation to report the changed property’s name along with its old and new values. Kotlin also provides Delegates.observable for this notification pattern. section 9.5.3 section 9.5.3

Choose delegation when the behavior is mostly already available elsewhere:

  • Delegate an interface when a wrapper should inherit ordinary operations from a contained implementation and customize only selected methods. section 4.3.3
  • Delegate a property when several accessors would repeat storage, validation, notification, or other shared logic. section 9.5
  • Override only the operations that differ, leaving unmodified interface methods to compiler-generated forwarding. section 4.3.3

How Kotlin in Action, 2E covers it

How deep it goes
Explains compiler-generated class forwarding and property delegates through observable-property refactoring, including getValue and setValue conventions.
Examples
Uses a CountingSet wrapper and observable Person age and salary properties to demonstrate selective forwarding.
What it assumes
Builds from interfaces, collections, properties, backing fields, and observer callbacks rather than assuming advanced delegation knowledge.
What you can do after
Apply it via Kotlin’s by syntax and Delegates.observable to customize selected behavior without rewriting routine forwarding code.
How it connects
Connects delegation with interfaces, decorators, collections, delegated properties, observers, and backing fields.

Also explained in

Compare how 2 books explain delegation →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Kotlin in Action, 2E. The section links point to the parts of the book it draws on.