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.