Bird
Raised Fist0
Kotlinprogramming~10 mins

Why delegation avoids inheritance in Kotlin - Visual Breakdown

Choose your learning style10 modes available
Concept Flow - Why delegation avoids inheritance
Start
↓
Define Interface
↓
Create Class A (implements Interface)
↓
Create Class B (delegates to Class A)
↓
Use Class B instance
↓
Calls forwarded to Class A
↓
Avoids inheritance issues
↓
End
Shows how delegation forwards calls to another class instead of inheriting, avoiding tight coupling and allowing flexible behavior.
Execution Sample
Kotlin
interface Printer {
    fun print()
}

class RealPrinter : Printer {
    override fun print() = println("Printing from RealPrinter")
}

class DelegatingPrinter(printer: Printer) : Printer by printer

fun main() {
    val real = RealPrinter()
    val delegator = DelegatingPrinter(real)
    delegator.print()
}
This code shows a class delegating the print() call to another class instead of inheriting from it.
Execution Table
StepActionEvaluationResult
1Create RealPrinter instanceRealPrinter()real = RealPrinter instance
2Create DelegatingPrinter with realDelegatingPrinter(real)delegator delegates to real
3Call delegator.print()delegator.print()Call forwarded to real.print()
4real.print() executesprintln("Printing from RealPrinter")Output: Printing from RealPrinter
5End of mainNo more callsProgram ends
💡 Program ends after delegator.print() call is forwarded and executed
Variable Tracker
VariableStartAfter Step 1After Step 2After Step 3Final
realnullRealPrinter instanceRealPrinter instanceRealPrinter instanceRealPrinter instance
delegatornullnullDelegatingPrinter instance (delegates to real)DelegatingPrinter instanceDelegatingPrinter instance
Key Moments - 3 Insights
Why doesn't DelegatingPrinter inherit from RealPrinter?
DelegatingPrinter uses delegation to forward calls to RealPrinter instead of inheriting, so it avoids tight coupling and allows changing behavior by swapping the delegate (see execution_table step 2 and 3).
How does delegator.print() call reach RealPrinter's print()?
Delegation automatically forwards the print() call from DelegatingPrinter to the RealPrinter instance it holds (see execution_table step 3 and 4).
What problem does delegation solve compared to inheritance?
Delegation avoids the rigid class hierarchy and tight coupling of inheritance by forwarding calls to a contained object, allowing more flexible code reuse (see concept_flow and execution_table).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the value of 'delegator' after step 2?
ARealPrinter instance
BDelegatingPrinter instance delegating to real
Cnull
DPrinter interface
💡 Hint
Check variable_tracker row for 'delegator' after step 2
At which step does the actual print output happen?
AStep 2
BStep 3
CStep 4
DStep 5
💡 Hint
Look at execution_table where println is called
If DelegatingPrinter inherited from RealPrinter instead of delegating, what would change?
ADelegatingPrinter would be tightly coupled to RealPrinter
BDelegation would be more flexible
CCalls would still be forwarded automatically
DNo difference in behavior
💡 Hint
Refer to key_moments about inheritance vs delegation
Concept Snapshot
Delegation in Kotlin lets a class forward interface calls to another object.
Syntax: class B(printer: Printer) : Printer by printer
Avoids tight coupling of inheritance.
Allows flexible behavior by swapping delegate.
Calls to B are forwarded to the delegate object.
Useful to reuse code without subclassing.
Full Transcript
This example shows how delegation avoids inheritance in Kotlin. We define an interface Printer with a print() function. RealPrinter implements Printer and prints a message. DelegatingPrinter takes a Printer object and delegates all calls to it using 'by'. When we call print() on DelegatingPrinter, it forwards the call to RealPrinter's print(). This avoids inheritance's tight coupling and rigid hierarchy by forwarding calls to a contained object. The execution table traces creating instances and forwarding calls step-by-step. Variable tracker shows how variables change. Key moments clarify why delegation is preferred over inheritance here. The visual quiz tests understanding of delegation flow and differences from inheritance. The snapshot summarizes delegation syntax and benefits in Kotlin.

Practice

(1/5)
1. Why does Kotlin prefer delegation over inheritance in many cases?
easy
A. Inheritance is not supported in Kotlin.
B. Delegation requires less code than inheritance.
C. Delegation allows sharing behavior without tightly coupling classes.
D. Delegation makes classes run faster.

Solution

  1. Step 1: Understand inheritance coupling

    Inheritance creates a strong link between parent and child classes, making changes harder.
  2. Step 2: Understand delegation flexibility

    Delegation shares behavior by forwarding calls, avoiding tight coupling and allowing easier changes.
  3. Final Answer:

    Delegation allows sharing behavior without tightly coupling classes. -> Option C
  4. Quick Check:

    Delegation avoids tight coupling = A [OK]
Hint: Delegation shares behavior without tight class links [OK]
Common Mistakes:
  • Thinking delegation is faster than inheritance
  • Believing Kotlin does not support inheritance
  • Confusing delegation with less code requirement
2. Which Kotlin syntax correctly shows delegation to an interface Printer by a class Document?
easy
A. class Document(printer: Printer) : Printer by printer
B. class Document : Printer(printer)
C. class Document implements Printer by printer
D. class Document extends Printer by printer

Solution

  1. Step 1: Recall Kotlin delegation syntax

    Kotlin uses class ClassName(...) : Interface by instance to delegate.
  2. Step 2: Match syntax to options

    class Document(printer: Printer) : Printer by printer matches the correct Kotlin delegation syntax exactly.
  3. Final Answer:

    class Document(printer: Printer) : Printer by printer -> Option A
  4. Quick Check:

    Delegation syntax uses ': Interface by instance' = B [OK]
Hint: Look for ': Interface by instance' syntax in Kotlin delegation [OK]
Common Mistakes:
  • Using 'implements' or 'extends' keywords (Java style)
  • Placing delegation inside parentheses incorrectly
  • Confusing inheritance syntax with delegation
3. What is the output of this Kotlin code?
interface Logger {
    fun log(msg: String)
}

class ConsoleLogger : Logger {
    override fun log(msg: String) {
        println("Console: $msg")
    }
}

class FileLogger : Logger {
    override fun log(msg: String) {
        println("File: $msg")
    }
}

class Application(logger: Logger) : Logger by logger

fun main() {
    val app = Application(ConsoleLogger())
    app.log("Start")
}
medium
A. File: Start
B. Console: Start
C. Application: Start
D. No output

Solution

  1. Step 1: Identify delegated logger instance

    The Application class delegates Logger to the passed instance, here ConsoleLogger.
  2. Step 2: Trace the log call

    Calling app.log("Start") calls ConsoleLogger.log, printing "Console: Start".
  3. Final Answer:

    Console: Start -> Option B
  4. Quick Check:

    Delegation calls ConsoleLogger.log = A [OK]
Hint: Delegation calls methods on passed instance, check which one is used [OK]
Common Mistakes:
  • Assuming FileLogger is used instead of ConsoleLogger
  • Expecting Application prefix in output
  • Thinking no output occurs without explicit print
4. Find the error in this Kotlin delegation code:
interface Worker {
    fun work()
}

class Engineer : Worker {
    override fun work() {
        println("Engineering work")
    }
}

class Manager(worker: Worker) : Worker {
    override fun work() {
        println("Managing")
    }
}
medium
A. Manager should delegate work to Worker using 'by' keyword.
B. Engineer class must not override work method.
C. Interface Worker cannot be implemented by classes.
D. Manager class should not have a constructor parameter.

Solution

  1. Step 1: Check delegation usage

    Manager has a Worker parameter but does not delegate using 'by', so delegation is missing.
  2. Step 2: Identify correct delegation syntax

    To delegate, Manager should declare: class Manager(worker: Worker) : Worker by worker.
  3. Final Answer:

    Manager should delegate work to Worker using 'by' keyword. -> Option A
  4. Quick Check:

    Missing 'by' keyword for delegation = D [OK]
Hint: Delegation requires ': Interface by instance' syntax [OK]
Common Mistakes:
  • Thinking override is not needed in Engineer
  • Believing interfaces can't be implemented
  • Assuming constructor parameters are disallowed
5. You want to combine behaviors of two interfaces Reader and Writer in one class without inheritance. Which Kotlin approach best avoids inheritance problems?
hard
A. Copy all methods from Reader and Writer into one class manually.
B. Create a class that inherits from both interfaces directly.
C. Use inheritance from one interface and implement the other manually.
D. Use delegation to both interfaces by passing separate instances.

Solution

  1. Step 1: Understand multiple inheritance issues

    Inheriting from multiple interfaces can cause tight coupling and complexity.
  2. Step 2: Use delegation to combine behaviors safely

    Delegation allows combining behaviors by forwarding calls to separate instances, avoiding inheritance problems.
  3. Final Answer:

    Use delegation to both interfaces by passing separate instances. -> Option D
  4. Quick Check:

    Delegation combines behaviors safely = C [OK]
Hint: Delegate multiple interfaces to separate instances to avoid inheritance issues [OK]
Common Mistakes:
  • Trying multiple inheritance which Kotlin disallows
  • Manually copying methods causing code duplication
  • Mixing inheritance and manual implementation causing complexity
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard