Delegation vs Inheritance in Kotlin
Tags: kotlin, tutorial, oop, programming
Published: 2023-07-05 14:33:18

Hello, everyone! Welcome to the article about class delegation in Kotlin. This tutorial will help you understand how to use class delegation in Kotlin and when to use it instead of inheritance.

The examples in this article are not mine and were taken from [this article](https://medium.com/androiddevelopers/delegating-delegates-to-kotlin-ee0a0b21c52b) with some changes applied. It provides a good explanation but, to my mind, lacks some things crucial for understanding. So I brought them up here.

### Why use delegation instead of inheritance

Let’s say we want a list’s item to be recoverable after deletion. To achieve this, we need to implement `MutableList`, override the `remove` function, and create our own `recover` function. But to do this, we need to override other methods that the `MutableInterface` tells us. So we essentially need to create our own implementation of `MutableList`. That’s not a cool thing to do as all the code is already written for us.

To avoid creating our own list, we can extend `ArrayList` instead. But this approach is not good for abstraction. We don’t want this list to be an ArrayList. We don’t need `ArrayList`'s specific methods like `trimToSize`, `ensureCapacity`, `grow`, etc. We just want to have an additional function. 

So there is a better way to achieve this. And this is delegation. We want to have only `MutableList`'s functions overridden by `ArrayList` and our own implementation of `remove`.

### How the delegation pattern works

We need to create a new variable of the `ArrayList` type and, at the same time, implement `MutableList`. And then in all the overridden functions’ bodies, respective `ArrayList`'s methods should be called. For example,

```kotlin
class ListWithTrash <T>(override val size: Int) : MutableList<T> {

    private val innerList: MutableList<T> = ArrayList()

    // the variable for storing the last deleted item
    private var deletedItem : T? = null

    override fun remove(element: T): Boolean {
        deletedItem = element
        // calling ArrayList's method, not our implementation
        return innerList.remove(element)
    }

    // here is our own function for recovering elements
    fun recover(): T? {
        return deletedItem
    }

    override fun add(element: T): Boolean {
        // calling ArrayList's method, not our implementation
        innerList.add(element)
    }
}
```

In this example, we override only `add` and `remove` `MutableList`'s methods. But we have a bunch of other methods we have to override for this to compile. That’s a lot of boilerplate code!

### How to delegate using `by` keyword

Luckily, we don’t need to do this. That’s how it works internally. Kotlin provides first-party support for delegation, and all this is done automatically under the hood. A developer's task is to use the simple `by` keyword:

```kotlin
class ListWithTrash <T>(
    private val innerList: MutableList<T> = ArrayList()
) : MutableList<T> by innerList {
    private var deletedItem : T? = null
    override fun remove(element: T): Boolean {
        deletedItem = element
        return innerList.remove(element)
    }
    fun recover(): T? {
        return deletedItem
    }
}
```

In this example, the `innerList` variable was also moved into the constructor to let the users of `ListWithTrash` provide their own `ArrayList`. This allows them to specify the desired list’s properties, for example, its size.

This is called delegation because along with our own implementations, the rest of the functions are delegated to the other classes. In our case, we delegate `MutableList` implementation to `ArrayList`. The necessary functions are “provided by” `ArrayList`.

Again, `ArrayList`'s specific functions won’t work:

```kotlin
val listWithTrash = ListWithTrash<String>()
//    listWithTrash.trimToSize() // → exception! (ListWithTrash doesn't have this function)
```

If you need them, extend from `ArrayList` directly.

### Multiple delegation is… allowed

{% stackoverflow 44238951 %}

### Delegation vs Inheritance

Inheritance allows to get a ready implementation by extending from the respective class. Whereas class delegation allows making a custom inheritant without lowering the class in the hierarchy. This is done by “copying” the ready implementation from the delegate. Here is the scheme for our situation:

![Scheme with squares and arrows that demonsrates inheritance on the left side and delegation on the right side. Inheritance: ListWithTrash extends from ArrayLIst, which in turn implements MutableList. Delegation: both ArrayList and ListWithTrash implement MutableList, and there is a connection between ArrayList and ListWithTrash.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/13qxqwpex003lux7krtb.png)

This scheme is not entirely correct because `ArrayList` doesn’t extend from `MutableList` in Kotlin. But the idea stays the same — our class (`ListWithTrash`) and the delegate (`ArrayList`) are on the same level in the hierarchy. Check out the cover of this article.

When to use which? Use inheritance only when you are sure that your class and the class you inherit from share all the common traits. If you think your class doesn’t need some variables or methods from its possible parent, and “is a” relationship doesn’t apply, it’s better to use delegation.

> That’s it! If this article was helpful, please, like it and follow for more. If you have any questions or corrections, feel free to write in the comments.
>