Property delegation
In programming, there are a number of patterns that use properties, like lazy properties, property value injection, property binding, etc. In most languages, there is no easy way to extract such patterns, therefore developers tend to repeat the same patterns again and again, or they need to depend on complex libraries. In Kotlin, we extract repeatable property patterns using a feature that is (currently) unique to Kotlin: property delegation. This feature’s trademark is the by keyword, which is used between a property definition and a delegate specification. Together with some functions from Kotlin stdlib, here is an example usage of property delegation that we use to implement lazy or observable properties:
Later in this chapter, we will discuss both lazy and observable functions in detail. For now, all you need to know is that delegates are just functions; they are not Kotlin keywords (just like lazy in Scala or Swift). We can implement our own lazy function in a few simple lines of code. Just like many Kotlin libraries, we can also implement our own property delegates. Some good examples are View and Resource Binding, Dependency Injection0, and Data Binding.
How property delegation works
To understand how we can extract other common behaviors using property delegation, let’s start with a very simple property delegate. Let’s say we need to define properties with custom getters and setters that print their value changes1:
Even though token and attempts are of different types, the behavior of these two properties is nearly identical and can be extracted using property delegation.
Property delegation is based on the idea that a property is defined by its accessors: for val, it is a getter; for var, it is a getter and a setter. These functions can be delegated to another object’s methods:the getter will be delegated to the getValue function, and the setter to the setValue function. An object with these methods needs to be created and placed on the right side of the by keyword. To make our properties behave the same way as in the example above, we can create the following delegate:
To fully understand how property delegation works, take a look at what by is compiled to. The above token property will be compiled to something similar to the following code:
To make sure we understand this, let's look under the hood and check out what our Kotlin property delegate usage is compiled to.
// Java representation of this code:
@Nullable
private static final LoggingProperty token$delegate =
new LoggingProperty((Object)null);
@Nullable
public static final String getToken() {
return (String)token$delegate
.getValue((Object)null, $$delegatedProperties[0]);
}
public static final void setToken(@Nullable String var0) {
token$delegate
.setValue((Object)null, $$delegatedProperties[0], var0);
}
public static final void main() {
setToken("AAA");
String res = getToken();
System.out.println(res);
}
Let's analyze this step by step. When you get a property value, you call this property's getter; property delegation delegates this getter to the getValue function. When you set a property value, you are calling this property's setter; property delegation delegates this setter to the setValue function. This way, each delegate fully controls this property’s behavior.
Other getValue and setValue parameters
You might also have noticed that the getValue and setValue methods not only receive the value that was set to the property and decide what its getter returns, but they also receive a bounded reference to the property as well as a context (this). The reference to the property is most often used to get its name and sometimes to get information about annotations. The parameter referencing the receiver gives us information about where the function is used and who can use it.
The
KPropertytype will be better covered later in the Reflection chapter.
When we have multiple getValue and setValue methods but with different context types, different definitions of the same method will be chosen in different situations. This fact can be used in clever ways. For instance, we might need a delegate that can be used in different kinds of views, but it should behave differently with each of them based on what is offered by the context:
Implementing a custom property delegate
To make it possible to use an object as a property delegate, all it needs is the getValue operator for val and the getValue and setValue operators for var. Both getValue and setValue are operators, so they need the operator modifier. They need parameters for thisRef of any type (most likely Any?) and property of type KProperty<*>. setValue should additionally have a property for a value whose type should be the same type or a supertype of the type used by the property. The getValue result type should be the same type or a subtype of the type used by the property.
These methods can be member functions, but they can also be extension functions. For instance, Map<String, *> can be used as a property delegate thanks to the extension function below, which is defined in the standard library. We will discuss using Map<String, *> as a delegate later in this chapter.
When we define a delegate, it might be helpful to implement the ReadOnlyProperty interface (when we define a property delegate for val) or the ReadWriteProperty interface (when we define a property delegate for var) from Kotlin stdlib. These interfaces specify getValue and setValue with the correct parameters.
Notice how those interfaces use generic variance modifiers. Type parameter
Tis only used in in-positions, so it has the contravariantinmodifier. TheReadOnlyPropertyinterface uses the type parameterVonly in out-positions, so it has the covariantoutmodifier.
Both ReadOnlyProperty and ReadWriteProperty require two type arguments. The first is for the receiver type and is typically Any?, which allows our property delegate to be used in any context. The second argument should be the property's value type. If we define a property delegate for properties of a certain type, we set this type here. We can also use a generic type parameter in this type argument position.
Provide a delegate
This is a story as old as time. You delegate a task to another person, who, instead of doing it, delegates it to someone else. Objects in Kotlin can do the same. An object can define the provideDelegate method, which returns another object that will be used as a delegate.
The power of provideDelegate is that the object that is used on the right side of the by keyword does not need to be used as a delegate. So, for instance, an immutable object can provide a mutable delegate.
Let's see an example. Let's say you implement a library to make it easier to operate on values stored in preference files2. This is how you want your library to be used:
The bindToPreference function returns an object that can be used as a property delegate. But what if we want to make it possible to use Int or Boolean as delegates in the scope of PreferenceHolder?
This way, using delegates is similar to assigning some values; however, because delegates are used, some additional operations might be performed, such as binding these property values to preference file values.
It is problematic to use Int or Boolean as delegates because they are not implemented to be used this way. We could implement getValue and setValue to operate on preference files, but it would be harder to cache values. The simple solution is to define the provideDelegate extension function on Int and Boolean. This way, Int or Boolean can be used on the right side of by, but they can’t be used as delegates themselves.
We can also use the PropertyDelegateProvider interface, which specifies the provideDelegate function with appropriate arguments and result types. The two type parameters of PropertyDelegateProvider represent the receiver reference type and the type of the property we delegate.
Personally, I am not a fan of using raw values as delegates because I believe that additional function names improve readability. However, this is the best example of using
provideDelegateI could find.
Property delegates in Kotlin stdlib
Kotlin provides the following standard property delegates:
Delegates.notNulllazyDelegates.observableDelegates.vetoableMap<String, T>andMutableMap<String, T>
Let's discuss them individually and present their use cases.
The notNull delegate
I will start with the simplest property delegate, which is created using the notNull method from the Delegates object that is defined in Kotlin stdlib. It is an alternative to lateinit, so the property delegated to notNull behaves like a regular property but has no initial value. Therefore, if you try to get a value before setting it, this results in an exception.
Wherever possible, we should use the lateinit property instead of the notNull delegate for better performance because lateinit properties are faster. Currently, however, Kotlin does not support lateinit properties with types that associate with primitives, like Int or Boolean.
In such cases, we use the notNull delegate.
I often see this delegate used as part of DSL builders or for properties whose values are injected.
In the next part of this series, you will see other property delegates from Kotlin stdlib, together with their use cases. So, stay tuned!
This example use of Koin formally presents service location, not dependency injection.
I assume you are familiar with custom getters and setters. I explain them in the previous book from this series, Kotlin Essentials, in the Classes chapter.
Before you do this, consider the fact that there are already many similar libraries, such as PreferenceHolder, which I published years ago.

