Delegation & Delegated Properties (by)
Delegation uses the by keyword to hand a class's interface or a property's get/set logic to another object, letting Kotlin generate the forwarding code for you.
Learn Delegation & Delegated Properties (by) in our free Kotlin course — a beginner-friendly interactive lesson with worked examples, a practice exercise and…
Part of the free Kotlin course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
You'll learn class delegation ( class A : I by impl ), delegated properties ( by lazy , observable , by map ), and how to write a custom delegate with getValue / setValue .
What You'll Learn in This Lesson
1️⃣ Class Delegation: by an Implementation
With class A : I by impl , class A implements interface I by automatically forwarding every method to impl . You write zero boilerplate pass-through methods and override only the ones you want to change. This is Kotlin's built-in "favour composition over inheritance".
LoudPrinter inherits Printer 's contract from base but supplies its own print — composition without a class hierarchy.
2️⃣ Delegated Properties: lazy & observable
A delegated property hands its get/set to a helper via by . by lazy computes a value once, on first read, then caches it. Delegates.observable fires a callback after every change. The standard library ships these so you don't write the plumbing.
Notice "computing token" prints only once even though token is read twice — that's the lazy cache. And each assignment to level triggers the observer.
3️⃣ Writing a Custom Delegate
Any object can back a property if it provides getValue (and, for a var , setValue ) operator functions. Kotlin routes every read and write through them, handing over the owning object and a KProperty . This hook lets you transform, validate, or log values automatically.
Every write to code is uppercased on the way in — the property itself looks completely ordinary at the call site.
Your turn. Fill in the ___ , then run and compare.
Back read-only properties with a Map using by map — each property reads the map entry matching its own name.
📋 Quick Reference — Delegation
Practice quiz
What does 'class A : I by impl' do?
- Makes A implement I by forwarding calls to impl
- Makes A a subclass of impl
- Prevents A from implementing I
- Copies impl's source code into A
Answer: Makes A implement I by forwarding calls to impl. Class delegation makes A implement interface I by forwarding every call to impl.
In class delegation, what can you still do for specific methods?
- Nothing, all methods are fixed
- Delete them entirely
- Override just the ones you want to change
- Only rename them
Answer: Override just the ones you want to change. You override only the members you want to change; the rest are forwarded automatically.
What keyword introduces a delegated property?
- with
- as
- is
- by
Answer: by. The 'by' keyword hands a property's get/set logic to a delegate.
When is a 'by lazy' value computed?
- On first access, then cached
- When the object is constructed
- Every time it is read
- Never, until explicitly invoked
Answer: On first access, then cached. lazy computes on first read and caches the result for later reads.
What does Delegates.observable do?
- Caches the value once
- Makes the property read-only
- Stores the value in a database
- Runs a callback after every change to the property
Answer: Runs a callback after every change to the property. Delegates.observable fires a callback after each assignment.
What does a custom var delegate need?
- operator getValue and setValue functions
- Only a constructor
- An iterator() function
- A companion object
Answer: operator getValue and setValue functions. A var delegate needs operator fun getValue and operator fun setValue.
By default, how thread-safe is 'by lazy'?
- It is never thread-safe
- It computes the value at most once even under concurrent access
- It recomputes per thread
- It throws under concurrency
Answer: It computes the value at most once even under concurrent access. Default lazy is thread-safe, computing the value at most once even concurrently.
With 'val name: String by map', how is the value looked up?
- By the map's first entry
- By a hard-coded key
- By the property's own name as the key
- Randomly
Answer: By the property's own name as the key. Map-backed properties look up the entry whose key matches the property name.
Which arguments does a getValue operator receive?
- Only the value
- thisRef and a KProperty
- Nothing
- A list and an index
Answer: thisRef and a KProperty. getValue receives the owning object (thisRef) and a KProperty describing the property.
How does Delegates.vetoable differ from observable?
- It can reject a change by returning false
- It caches like lazy
- It runs before construction
- It cannot use a callback
Answer: It can reject a change by returning false. vetoable is like observable but can veto (reject) a change by returning false.