Caveats of Kotlin Delegation

Implementation caveat

In the example we’ve created so far, the Manager may delegate calls to an instance of a JavaProgrammer, but a reference to a Manager may not be assigned to a reference of a JavaProgrammer—that is, a Manager may use a JavaProgrammer, but a Manager may not be used as a JavaProgrammer. In other words, a Manager has a JavaProgrammer but is not a kind of JavaProgrammer. Thus, delegation offers reuse without accidentally leading to substitutability as inheritance does.

However, there’s one small consequence of how Kotlin implements delegation. The delegating class implements the delegating interface, so a reference to the delegating class may be assigned to a reference of the delegating interface. Likewise, a reference to a delegating class may be passed to methods that expect a delegate interface. In other words, for example, the following isn’t valid:

val coder: JavaProgrammer = doe //ERROR: type mismatch

But the following is possible in Kotlin:

val employee: Worker = doe

This means a Manager is a, or kind of a, Worker. The true intention of delegation is for a Manager to use a Worker, but Kotlin’s delegate implementation introduces a side effect that a Manager may be treated as a Worker.

Delegating to a property caveat

Also, use caution when delegating to a property. We passed a parameter of type Worker to the constructor of Manager, using val. In Prefer val over var, we discussed why we should prefer val over var. That recommendation is useful here too. If we decide to change the property that’s used as a delegate from val to var, a few consequences arise. Let’s see what those are with an example.

Here’s the full listing we’ll use for this example:

Get hands-on with 1200+ tech skills courses.