by Adam Arold
By the way — exploring delegation in Kotlin
Kotlin has an interesting keyword,
by, which can be used for delegation. There is a lot of confusion around it, so in this article we’ll clean that up.
If we check the keyword reference page of Kotlin,
by is listed there. It says that it is capable of two different things:
- delegates the implementation of an interface to another object
- delegates the implementation of accessors for a property to another object
I think this is the source of most confusion. After reading this article, you’ll be able to see that these two things are essentially the same in Kotlin.
Before we do that, we should clarify what delegation is in the first place. By perusing the related Wikipedia page we can find the following definition:
In software engineering, the delegation pattern is an object-oriented design pattern that allows object composition to achieve the same code reuse as inheritance.
I think this is a pretty accurate description, and it also comes with a Kotlin code example!
As we have seen above Kotlin supports delegation of an interface and delegation of accessors for a property. Let’s take a look at how they work in detail.
Delegation of an interface
For this exercise we’ll use
DefaultPositionable which is just an implementation of
The above functionality can be used without the
by keyword like this:
This involves a lot of boilerplate code as seen in the above example. The purpose of the
by keyword is to do away with this kind of drudgery. It allows object composition to achieve the same code reuse as inheritance:
So in a nutshell: with
by we get Item 16 from Effective Java for free. Pretty nifty, huh?
Taking a look under the hood
Now that we know how it works on the outside, let’s check out the internals. This is really important as we’ll see later. This is the Java code which will be generated from the
Rect implementation above:
You can do this yourself in IDEA by using
Tools > Kotlin > Show Kotlin Bytecode and then cli
So what Kotlin does is that it takes our delegate,
DefaultPositionable, puts it in the resulting class as a
private final field named
$$delegate_0 and adds implementations for all the methods of
Positionable and in them it calls our delegate.
If by eyeballing the above code you had guessed that we can have multiple delegates in a class, you’d be right! Let’s do just that by extracting
height into its own delegate:
Sizable we can have a class which has the same functionality as
Rect but with only delegates:
The resulting Java code is this:
This also means that with delegation we can unit test our building blocks in isolation (DefaultPositionable and DefaultSizable here). This is a significant improvement over inheritance in itself.
So it turns out that with the
by keyword we have a really powerful alternative to inheritance. The only limitation is that we have to use
interfaces on the right-hand side of
by:. Kotlin can only delegate to interfaces.
This also means that Kotlin supports Mixins or Multiple inheritance.
Remember that multiple inheritance comes in 3 “flavors” . They are inheritance of state, implementation and type. Java originally only supported multiple inheritance of type (with interfaces). Java 8 added support for multiple inheritance of implementation (with default methods). By using the
bykeyword we can have multiple inheritance of state as well!
Variations of interface delegation
There are many ways of using interface delegation, and not all them work in a way as you would expect.
Rect in fact could have been defined with all the examples below to similar effect, but with slight differences in utility:
RectWithConstructor lets us pass custom implementations of
Positionable to our Rect. With
RectWithProperty we can have access to our delegate within our Rect. With
RectWithDefaultValue we can achieve both while being able to just pass a
Position to the constructor if we are fine with the default value:
RectWithFunction is a bit of an outlier. It is there to demonstrate that we can also have functions producing delegates for us. This will be useful later when we’ll try to understand property delegation.
RectWithDefaultValueachieves multiple inheritance of state as well.
The pitfall of interface delegation
You might have wondered about what happens when we can not only pick an implementation for our delegate but change it at runtime:
This looks good, but if we take a peek at the generated Java code we’ll see a discrepancy:
Yep, if we make our delegate a
var and change it at runtime, it won’t change the actual delegate. It will happily set the value of the
positionable property and leave
$$delegate_0 unchanged. This can lead to pretty nasty problems if you forget this, so my advice is not to do this.
If you try to hack around this by renaming
$$delegate_0it won’t work — you’ll get a compiler error detailing a JVM name clash.
You might have seen code like this before:
and wondered about why we have a keyword for seemingly unrelated things. To fully understand how this works we need to take a look at the difference between properties and fields.
Properties and Fields
In Java we have fields and they look like this:
There are no methods, no strings attached, just our solitary field. If we write the same class in Kotlin, while it might look similar:
the Java code generated from it will be a bit different:
So here is the difference: fields are just solitary slots which store data. Properties on the other hand have getters and if we declared them as a
var they will also have setters. This difference is very important. We’ll see how this makes it possible to have not only interface delegates but property delegates as well!
There are cases when the Kotlin compiler won’t even declare a backing field for a property. For example with this Kotlin code:
The generated Java code will only contain a method. Since the value of
foo can’t be changed and it is pre-determined:
There are more to properties but I won’t explain them here. The Kotlin docs are rather verbose about this topic. You can check them out here.
Peeking at an actual property delegate
With this knowledge we have everything to understand how property delegation works. If we take a look at the docs for this topic (which I recommend reading thoroughly) we can see this:
There are certain common kinds of properties, that, though we can implement them manually every time we need them, would be very nice to implement once and for all, and put into a library. Examples include:
- lazy properties: the value gets computed only upon first access;
- observable properties: listeners get notified about changes to this property;
- storing properties in a map, instead of a separate field for each property.
To cover these (and other) cases, Kotlin supports delegated properties:
Let’s revisit the example above which has a
lazy property delegate:
If we take a look at what the
lazy function does:
we can see that it returns a
SynchronizedLazyImpl which is a class that implements
Lazy also comes with an extension function:
which is there to implement the
You can read more about operator overloading here.
The main point here is that delegating to a property uses the exact same mechanisms behind the scenes as interface delegation. The differences which cause the confusion are the
setValue operators. We need them to implement within our property delegates. Not because of how delegation works, but because how overriding property access operators work.
lazy() to delegate to an instance of
Lazy is the same on the code level as calling
fetchPositionable() in the example above to delegate to an instance of
How to write our own delegate
Kotlin gives us two interfaces to use for this purpose:
This further reinforces the similarity between the two kinds of delegation. Let’s take a look at how we can implement a property which is not initialized during object construction but at a later time, but still won’t let us read
null values from it:
Note that this class is in the Kotlin stdlib, but it is not well known that it is there.
We can also add a factory method to produce it:
and we can use it like this:
Taking a look at the Java code
If we decompile the Java bytecode from
SomeClass above, we’ll see this:
Looks strangely familiar, no? Kotlin generates a field for our delegate. (
someValue$delegate). Kotlin uses it when either the getter or the setter of our property is called.
By having properties instead of fields, property delegation can work out of the box. Properties come with getters and setters. Kotlin can provide custom implementations for them when we want to use property delegates.
With interface delegation we can have all three kinds of multiple inheritance: state, implementation, and type. It also lets us use composition without the boilerplate.
And also we now understand what the documentation says about delegation. With interface delegation we delegate the implementation of an interface to another object. With property delegation we delegate the implementation of accessors for a property to another object.
Now, with all this new knowledge under our belt let’s go forth, and Kode on!
Thanks for reading! You can read more of my articles on my blog.