How Kotlin’s Class delegation works and DI 101

Chang W. Doh
TIL: Kotlin in Practice
5 min readSep 17, 2017
Image source: https://pixabay.com/photo-2542109/

In my last article, we’ve taken a look at Delegated Properties and lazy initialization in Kotlin. Today we’ll have a look at the other part, Class delegation.

Warmup

To prevent injuries, let’s relax our fingers. As you know, we can write a code with interface to define required prototypes for your classes. Here’s a such code.

interface Base {
fun printX()
}


class BaseImpl(val x: Int) : Base {
override fun printX() { print(x) }
}

And its decompiled Java code:

public interface Base {
void printX();
}


public final class BaseImpl implements Base {
private final int x;

public void printX() {
int var1 = this.x;
System.out.print(var1);
}


public final int getX() { return this.x; }
public BaseImpl(int x) { this.x = x; }
}

Yes, there’s no any special part, easy to understand. What’re the benefits of using interface instead of inheritance? :)

What’s Class Delegation?

My father always said manual is right. Ok, let’s see the reference:

The by-clause in the supertype list for Derived indicates that b will be stored internally in objects of Derived and the compiler will generate all the methods of Base that forward to b.

In other words, you can declare an class as the delegation of another class to make callable for all the methods of it.

interface A { ... }
class B : A { }
val b = B()// initiate C, and delegate all methods of B defined in A
class C : A by b

If there’s a class B which implements interface A, you can delegate all methods of b to class C by interface A. It’s called Class Delegation.

Internally, b will be stored as the private field in C, and all implemented methods of B will be generated as static methods which refer to that private field b in C. Let’s go to check this.

Class delegation under the hood

How this work? Here’s a simple code:

interface Base {
fun printX()
}

class BaseImpl(val x: Int) : Base {
override fun printX() { print(x) }
}
val baseImpl = BaseImpl(10)class Derived(baseImpl: Base) : Base by baseImpl

Above code will be generated like the following code in Java:

public interface Base {
void printX();
}
public final class BaseImpl implements Base {
private final int x;
public void printX() {
int var1 = this.x;
System.out.print(var1);
}
// ...
}
public final class Derived implements Base {
// $FF: synthetic field
private final Base $$delegate_0;
public Derived(@NotNull Base baseImpl) {
Intrinsics.checkParameterIsNotNull(baseImpl, "baseImpl");
super();
this.$$delegate_0 = baseImpl;
}
public void printX() {
this.$$delegate_0.printX();
}
}

As you can see, $$delegate_0 is generated to refer to the origin instance of Base, and printX() is also generated to call printX() of $$delegate_0. So, you can call printX() method without the reference by wrapped method in class Derived.

Methods which aren’t derived from the interface

Sure, you can declare other methods and properties which aren’t derived from the interface like:

interface Base {
fun printX()
}

class BaseImpl(val x: Int) : Base {
override fun printX() { print(x) }

private var y : Int = 10
fun printY() { print(y) }
}

It’s decompiled Java code:

public interface Base {
void printX();
}

public final class BaseImpl implements Base {
public final void printY() {
int var1 = this.y;
System.out.print(var1);
}

// ...
}

public final class Derived implements Base {
// $FF: synthetic field
private final BaseImpl $$delegate_0;

public Derived(@NotNull Base baseImpl) {
Intrinsics.checkParameterIsNotNull(baseImpl, "baseImpl");
super();
this.$$delegate_0 = new BaseImpl(10);
}

public void printX() {
this.$$delegate_0.printX();
}

}

Yeah, as you can suppose, class Derived doesn’t have printY() method because it doesn’t exist in the interface Base.

Why do we use Class delegation?

Now, we can suppose class delegation is easier way to use implemented methods without a reference to its instance. At this point, you can ask me why we use this.

Basically, Kotlin’s classes is blocked from the inheritance. So, if you want make them inheritable, you should use open.

Well, in my thought, Kotlin language designers looks like don’t want making issues by complex dependencies in inheritances of class.

Kotlin’s Class Delegation is the another option, supporting Delegate Pattern. The good parts of it are:

  • Alternative to inheritance without boilerplate code.
  • Only granted method by interface can be invoked.
  • Protects from accessing the instance directly by storing it in private field.

The most important part of it is that Class Delegation enables a module flexible and configurable. Let’s see the following code.

interface Vehicle {
fun go(): String
}
class CarImpl(val where: String): Vehicle {
override fun go() = "is going to $where"
}
class AirplaneImpl(val where: String): Vehicle {
override fun go() = "is flying to $where"
}
class CarOrAirplane(
val model: String,
impl: Vehicle
): Vehicle by impl {
fun tellMeYourTrip() {
println("$model ${go()}")
}
}
fun main(args: Array<String>) {
val myAirbus330
= CarOrAirplane("Lamborghini", CarImpl("Seoul"))
val myBoeing337
= CarOrAirplane("Boeing 337", AirplaneImpl("Seoul"))

myAirbus330.tellMeYourTrip()
myBoeing337.tellMeYourTrip()
}

The above code shows how you can implement encapsulation and polymorphism by Class Delegation.

Copy-kitty example: CoffeeMaker

CoffeeMaker example of Dagger2 is awesome example to explain how DI works. I’ve just wrote similar code with Class delegation.

I didn’t intend to convert the original code to Kotlin’s perfectly, but I wanna show how to write code with class delegation instead of inheritance.

I hope this code is enough to understand how to write simple Dependency Injection code with Class Delegation.

To be frankly with you, the hardest part was that I didn’t know how the Thermosiphon works. 🤣 I had to googled to learn about it. if you wanna know, check here and here.

Class delegation make code more flexible

Delegation pattern is powerful. It protects your code base from some bad events such as requirement changes. Kotlin’s Class delegation is fully supported from the language. It means there’s no additional coding cost such as boilerplate to implement it. :)

Define your interfaces carefully, then use them to inject dependencies. It give your code flexibility, but less typing than before. Hope to hear your experiences. :)

If you find wrong part, typo error or any strange part. Feel free to address them. I always welcome your comment or email! :)

--

--

Chang W. Doh
TIL: Kotlin in Practice

I’m doing something looks like development. Community diver. ex-Google Developer Expert for Web 😎