Kotlin type Extensions
Tags: kotlin, functional
Published: 2019-12-14 17:18:34

*Assumptions*

* General understanding of kotlin

The kotlin type system is extremely powerful. It provides a wealth of useful tools: data classes, interfaces with default implemetnations, sealed classes, object types, final by default on concrete types - the list goes on.

However, there is one feature that in my mind, that stands out as being overlooked but incredibly valuable - Extension Types.

### What is an extension type?

Lets take  a simple class as an example:

```kotlin
import java.util.concurrent.LinkedBlockingQueue

class Context<T> {
    private val items: Queue<T> = LinkedBlockingQueue()
    
    fun add(item: T) {
        items.add(item)
    }
    
    fun drainAll(): List<T> {
        val result = items.toList()
        items.clear()
        return result
    }
}
```

Lets say you had some common methods that you had to run on this class, for example a "merge" method.

In java, you would create static methods like so:

```kotlin
fun <T> merge(context1: Context<T>, context2: Context<T>): Context<T> {
    val newContext = Context<T>()
    context1.drainAll().forEach { newContext.add(it) }
    context2.drainAll().forEach { newContext.add(it) }
    return newContext
}
```

You could then invoke this method like so:

```kotlin
val context1: Context<T>
val context2: Context<T>

merge(context1, context2)

```

This implementation works, even if it isn't the most elegant it is pragmatic.  Its easy to test, and the semantics are clear.

Extension methods allow us to express the exact same code a little bit more elegantly:

```kotlin
fun Context<T>.merge(context: Context<T>): Context<T> {
    val newContext = Context<T>()
    this.drainAll().forEach { newContext.add(it) }
    context.drainAll().forEach { newContext.add(it_) }
    return newContext
}
```

You now invoke `merge` on a context object like you would any normal method on the `Context<T>` class

```kotlin
val context1: Context<T>
val context2: Context<T>

context1.merge(context2)
```

The function definition`fun Context<T>.merge(...)` tells the compiler within this method, the keyword`this` references the `Context<T>` on which `merge` was invoked.

### Extension type implementation and limitations

At compile time, extension types become a static method that takes in an extra preceding type argument for the first type.  In fact, in the above example, the static method example is conceptually what the compiler creates from the extension method example.

Extension methods have a few limitations:
* extension methods cannot access protected  or private members
* extension methods cannot override existing methods
* *extensions can be messy and can make code much much worse if misused.*

### Extension Functions

Above we saw a method with an extension type.  Kotlin takes this one step further by also providing the ability to also apply this same principle to functions.

```kotlin
fun <T> withContext(body: Context<T>.() -> Unit): List<T> {
    val context = Context<T>()
    context.body()
    return context.drainAll()
}
```


```kotlin
val result: List<String> = withContext<String> {
    add("hello")
    add("goodbye")
}
```

Just  like extension methods, extention functions expose the type on the left side of the function parameter declaration as "this" within the function.  The following screenshot shows the IDE identifying `this` in the block inside of withContext:

![IDE extension function](https://thepracticaldev.s3.amazonaws.com/i/pu86eb2wgx3r8jabg8nk.png)

### Extension methods on type parameters

The kotline standard library is full of excellent extension methods like the [kotlin use function](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/use.html)

First, lets naively attempt to implement use:

```kotlin
inline fun <R> Closeable?.uselessUse(block: (Closeable?) -> R): R { ... }

var stream: BufferedInputStream = BufferedInputStream(FileInputStream(File("my-file.txt")))
it.uselessUse { closable: Closeable? ->
    //doesn't know closable is a BufferedInputStream
    false
}
```
In this implementation, the `block` loses context of what type of closable `uselessUse` was called on.  This makes it difficult to interact with the `Closeable` inside of block, which undermines the utility of this method.


```kotlin
inline fun <T : Closeable?, R> T.use(block: (T) -> R): R { ... }

var stream: BufferedInputStream = BufferedInputStream(FileInputStream(File("my-file.txt")))
stream.use { bufferedInputStream: BufferedInputStream ->
    //knows that the closable was a BufferedInputStream
    String(bufferedInputStream.readAllBytes())
}
```

Notice how the `use` function extends a type parameter `T: Closable?` instead of a concrete type `Closable?`.  This allows the `block` to have context of what type of `Closeable` is being used, and allows the user to take full advantage of auto-closable functionality.

## Okay, so what?

In Java, auto closable was implemented as a language feature in Java 7.  It worked, and it provided some syntactic sugar, but it was incredibly limited in scope.  With extension functions, the Kotlin standard library provides an implementation for auto closable and describes a reproducible pattern for extending the language itself.

Extension functions are the main mechanism through which kotlin enables DSL implementation. In my next post I'll go into detail about how this can be done.