Interface delegation in Kotlin

Giuseppe Villani
2 min readAug 10, 2019

--

Featured in Kotlin Weekly Issue #179

Interface delegation, in Kotlin, is a simple yet powerful technique that allows a class to delegate the actual implementation of the interfaces, to separate objects.

Let’s go straight to an example. Given the following interfaces:

interface SteeringControl {
fun turnLeft()
fun turnRight()
}
interface EngineType {
val type: String
}

NOTE: Kotlin interfaces support both abstract methods and abstract properties.

Now we create a class that implements both interfaces:

class FiatBravo : EngineType, SteeringControl {
override fun turnLeft() {
println("Rotate steering wheel counterclockwise")
}
override fun turnRight() {
println("Rotate steering wheel clockwise")
}
override val type: String
get() = "petrol"
}

Nothing new here, just regular interfaces implementation. The new class FiatBravo is directly implementing the abstract methods and property defined in the interfaces.

We can notice, however, that many other vehicles are probably going to use the same steering control system, or even more likely they are going to have the same engine type. What we can do then is to use separate objects that know about specific implementations (specific engine type, or specific steering control system):

object Petrol : EngineType {
override val type: String
get() = "petrol"
}

object Diesel : EngineType {
override val type: String
get() = "diesel"
}

object SteeringWheel : SteeringControl {
override fun turnLeft() {
println("Rotate steering wheel counterclockwise")
}

override fun turnRight() {
println("Rotate steering wheel clockwise")
}
}
object HandleBar: SteeringControl {
override fun turnLeft() {
println("Turn handlebar to left")
}

override fun turnRight() {
println("Turn handlebar to right")
}
}

NOTE: adding the object keyword allows to reuse the same instance (in Kotlin it is the way you define a singleton).

Now we can delegate the actual implementation to those objects. So our FiatBravo class becomes:

class FiatBravo : EngineType by Petrol, 
SteeringControl by SteeringWheel

Now everything is handled by interface delegation. Also note that the curly braces are not required anymore, since the body is empty.
Using the keyword by we are telling that we want to use a specific object as responsible for implementing the interface.

We can use our class as following:

val fiatBravo = FiatBravo()
fiatBravo.turnLeft()
fiatBravo.turnRight()
println(“Engine type: ${fiatBravo.type}”)

The same vehicleFiatBravo is actually produced in different version (diesel and petrol). So it might be useful to pass the engine type as parameter. We can modify our main constructor class as following:

class FiatBravo(engineType: EngineType) : EngineType by engineType, 
SteeringControl by SteeringWheel

In this way we can pass the engine type we need, using the corresponding object:

val fiatBravoPetrol = FiatBravo(Petrol)
val fiatBravoDiesel = FiatBravo(Diesel)

As you can see Interface Delegation is a powerful tool. Consider using it whenever you want to reuse the same implementation across different classes that are extending the same interfaces.

--

--

Giuseppe Villani

Android developer — Passionate about mobile development, clean code and reactive programming