Mastering Kotlin Delegation: From Property Delegates to Class Composition
kouta222

kouta222 @kouta222

About: Software engineer mainly frontend developing / seek for an engineer position in usa

Location:
Tokyo,japan
Joined:
Jan 21, 2024

Mastering Kotlin Delegation: From Property Delegates to Class Composition

Publish Date: Aug 20
2 0

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>

Enter fullscreen mode Exit fullscreen mode

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"
}

Enter fullscreen mode Exit fullscreen mode

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")
}

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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:

  1. Generates an auxiliary hidden property (e.g., prop$delegate).
  2. Makes the original property’s getter/setter call into the delegate.

For example:

val name: String by lazy { "Kotlin" }

Enter fullscreen mode Exit fullscreen mode

translates to something like:

private val name$delegate = lazy { "Kotlin" }
val name: String
    get() = name$delegate.value

Enter fullscreen mode Exit fullscreen mode

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()
  • If it describes state → use a property
    • e.g. name, lastName, weight

More: Kotlin Academy Blog


References

Comments 0 total

    Add comment