A Look at Kotlin's Delegation
A look at the Delegation Pattern in Kotlin.
Join the DZone community and get the full member experience.Join For Free
Kotlin offers many exciting features. In general, developers tend to cite null safety as their favorite. For me, it's function extensions. But delegation comes a close second.
The Delegation Pattern
The delegation pattern is described in the GoF book:
Delegation is a way to make composition as powerful for reuse as inheritance [Lie86, JZ91]. In delegation, two objects are involved in handling a request: a receiving object delegates operations to its delegate. This is analogous to subclasses deferring requests to parent classes. But with inheritance, an inherited operation can always refer to the receiving object through the
thismember variable in C++ and
selfin Smalltalk. To achieve the same effect with delegation, the receiver passes itself to the delegate to let the delegated operation refer to the receiver.
Delegation is critical when one chooses composition over inheritance.
Manual and Native Delegation
In Java, you need to code delegation manually. The example above translates into the following code:
Kotlin handles the delegation natively using the keyword
by. You can write the same code in Kotlin like this:
- With this, you can call
As explained in the docs:
The by-clause in the supertype list for
bwill be stored internally in objects of
Delegate, and the compiler will generate all the methods of
Bthat forward to
Kotlin also offers delegated properties, a property that delegates its getter (and its setter if a
var) to "something else". A delegated property also uses the
by keyword. A couple of out-of-the-box delegates are available through the standard library.
- Non-null delegate: A non-
nulldelegate behaves the same way as the
lazyinitkeyword: if one uses the variable before one has initialized it to a non
nullvalue, it will throw an
- Lazy delegate: A lazy delegate computes the value on the first access, stores it, and then returns the stored value. As its name implies, you use
lazywhen the value is expensive to compute and doesn't change after computation.Kotlin
- Observable: An observable delegate offers a hook when the value is accessed so you can execute code afterward.
- Vetoable: A vetoable delegate is the opposite of the observable. It offers a hook that executes before. If this hook returns
true, the set of the value executes as expected; if it returns
false, the set doesn't happen.Kotlin
Your Own Delegated Property
If you want to create your own delegated property, it needs to point to a class that has:
operator fun getValue(thisRef: T, prop: KProperty): Uoperator function for fields whose value is immutable
- An extra
operator fun getValue(thisRef: T, prop: KProperty, value: U)if it's mutable
Tis the class' type
thisRefis the class instance
valueis the new value
propis the property itself
As an illustration, let's implement a distributed cache delegated property based on Hazelcast IMDG.
- Create a reference to a Hazelcast
- Get the value from the
- Set the value in the
Using the above delegate is straightforward:
The delegate pattern is ubiquitous in the Object-Oriented Programming world. Some languages, such as Kotlin, provides a native implementation. But delegation doesn't stop at the class level. Kotlin does provide delegation at the property level. It provides some out-of-the-box delegates, but you can easily create your own.
Originally published at A Java Geek on April 18th, 2021
Published at DZone with permission of Nicolas Fränkel, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.