Higher-order functions in Kotlin
Published: 2020-06-04 08:12:41

Kotlin is a language where functions are first class citizens. This allow us to manipulate them as we please.  

Today we will see what **higher-order functions** are, why do they matter and how to create them in Kotlin.  

## My functions are High

In functional programming (FP for the rest of the post), as the name suggests, functions are the base building blocks of the code. 

Often in OOP, a function takes some data as an input, process them, and returns an object (representing some other data).

In FP you can also find *higher-order functions* : functions that returns another function **or** functions that take one or more function as arguments.  

### Show me the code 

{% gist https://gist.github.com/rafipanoyan/8d2c1ac4430ae2c7ff17285b05e34d12 %}

Step by step, here is what's happening : 

```kotlin
fun multiplyBy(multiplier: Int): (Int) -> Int {
    return { value -> value * multiplier }
}
```

If we look at the `multiplyBy` function signature and return type, we can tell that :
- it takes an `Int`
- it returns a `function that takes an Int and returns an Int`.

**Returning a function is a typical signature of a higher-order function.**

The `multiplyBy` body consist of returning a new function which takes a `value` in parameter and returns that value multiplied by our `multiplier`.

```kotlin
val by3 = multiplyBy(3)
```

Here we call our higher-order function to create a new function named `by3` which will multiply by 3 every parameter we give it.

```kotlin
val result = by3(5)
```

Clearly, we execute `by3` with 5 as a parameter. The result is 15.

### Ok but, why ?!

If you would have asked me this question yesterday, I would have said... I don't know.

I always liked this "function that creates other function" principle in FP, but never seemed to exceed the academic meaning of it.

Yes, you can now write this : 

```kotlin 
val by5 = multiplyBy(5)
```

but in a real application, what's the matter ?

Unless...

## My functions are Small

After many years studying FP, writing higher-order functions (HOF for the rest of the post) in Clojure, Haskell or Kotlin, just for the sake of learning a new language, I finally came across a real use case where it saved me a good amount of duplicate code. 

I will now develop a concrete (and very simplified) example from an Android application I'm developping.

### Context

This application holds a list of dated objects (`Record`). The user should be able to filter these records by year and by month independently.  

Given this list : 
- Record 1 : 1st january 2019
- Record 2 : 1st march 2020
- Record 3 : 1st may 2020

I should get these filters : 

Years : 2019 2020  
Months : january march may

From a single source of data I must get 2 distinct lists based on 2 distinct fields of the record's date (the year and the month).

### First try

I expose these filters to my UI with two different `LiveData`, one for the years and one for the months (if you don't know what a [LiveData](https://developer.android.com/topic/libraries/architecture/livedata) is, just think about them as Observable data).  

The general idea of the flow is as follows : 

- get the list of all records with `getRecords.getAll()`
- map this list from `List<Record>` to `List<Int>` representing the list of years or months of the filters
  - we call [`distinctBy`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/distinct-by.html) to obtain a list of distinct records based on their year or month
  - we [`map`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/map.html) this new list to extract only the corresponding field of the date
  - we sort the final list of years or months

{% gist https://gist.github.com/rafipanoyan/03bfef25b5c9fbc09cda3ea9a65bbc7c %}

This piece of code has several issues. One of them being that the two filters have almost exactly the same code, and only this part differs :

```kotlin
.distinctBy { record ->
    return@distinctBy Calendar.getInstance().apply {
        time = record.date.value
    }[Calendar.YEAR]
}
.map { record ->
    return@map Calendar.getInstance().apply {
        time = record.date.value
    }[Calendar.YEAR]
}

.distinctBy { record ->
    return@distinctBy Calendar.getInstance().apply {
        time = record.date.value
    }[Calendar.MONTH]
}
.map { record ->
    return@map Calendar.getInstance().apply {
        time = record.date.value
    }[Calendar.MONTH]
}
```

This seems to be a good candidate for a refact. 

#### Quick note 

These functions (`map`, `distinctBy`, `filter`, etc.) are all HOF as well, because they take another function as argument (here it's the lambdas we are passing).  They implement [Function composition](https://en.wikipedia.org/wiki/Function_composition_(computer_science)) and it's one of the main use of HOF.

### The OOP-way

Instinctively in OOP, I would have created a function taking two parameters : a record and the calendar field to read from the `Calendar` instance.

```kotlin
private fun readCalendarField(record: Record, calendarField: Int) {
    return Calendar.getInstance().apply {
        time = record.date.value
    }[calendarField]
}
```

We would use it as follows :

```kotlin
// years filter
.distinctBy { record ->
    return@distinctBy readCalendarField(record, Calendar.YEAR)
}
.map { record ->
    return@map readCalendarField(record, Calendar.YEAR)
}

// months filter
.distinctBy { record ->
    return@distinctBy readCalendarField(record, Calendar.MONTH)
}
.map { record ->
    return@map readCalendarField(record, Calendar.MONTH)
}
```

Better. We avoided the duplicate implementation of reading the calendar field, but we still have duplication.  

For each filter, the exact same lambda has been created twice : one for `distinctBy` and another for `map`. How can we avoid that ?

### The FP-way

You saw it coming, let's introduce our higher-order function !  

We need to write a function that creates a function, very similar to the lambda we were creating twice, but with an additional parameter : the calendar field.

```kotlin
private fun newCalendarFieldGetter(calendarField: Int): (Record) -> Int = 
    { record ->
        Calendar.getInstance().apply {
            time = record.date.value
        }[calendarField]
    }
```
The return type of our function is key here : `(Record) -> Int`. It complies to both `distinctBy` and `map` input type which is `(T) -> R`.  
Additionnaly, our HOF asks for a calendar field to parameterize the new function that it creates.

We can now write this :

{% gist https://gist.github.com/rafipanoyan/cfa5a8c043ae4416e0e175634228a634 %}

This starts to look pretty good ! We take advantage of the fact that `newCalendarFieldGetter` is a [pure function](https://en.wikipedia.org/wiki/Pure_function) (thus has no side effects) to share the same instance for `dinstinctBy` and `map`.  

Now let's tackle the last duplication of this snippet : the two filters are exactly identical, only differing by the calendar field parameter. 

Following the exact same logic as previously, we can create a parameterized function to fill the `getRecords.getAll().map()` input.

### Perfection 

The `map` function we are trying to call needs one parameter of type `suspend (T) -> R`.  
Our new higher-order function will comply to this by returning a `suspend (List<Record>) -> List<Int>`, and it will take one more parameter, the calendar field.

```kotlin 
private fun getDistinctDateFields(calendarField: Int)
    : suspend (List<Record>) -> List<Int> = { records ->
        val fieldGetter = newCalendarFieldGetter(calendarField)
        records
            .asSequence()
            .distinctBy(fieldGetter)
            .map(fieldGetter)
            .sorted()
            .toList()
    }
```

The previously duplicated block is now generic and can be used to extract a list of any disctinct field of the `Record` date !  

Here is how the entire code looks like.

{% gist https://gist.github.com/rafipanoyan/fb1965f349db89d8dc69456e545463aa %}

With this version, adding a third filter on another field of the date, let's say DAY_OF_MONTH, is quit easy !

## Final thoughts

This kind of refact is not the most impressive thing you can do with HOF, but it was simple enough to understand how it works in Kotlin and how to use them with common collection manipulation functions as `map`, `filter` etc, which also are higher-order functions.

[Function composition](https://en.wikipedia.org/wiki/Function_composition_(computer_science)) is a frequent use of HOF, I will certainly post an article about this in the future.

The goal is not to use them everywhere. A good balance must be found between readability, maintainability and optimization (as every aspect of programming). However it's always interesting to learn more new tools to helps us choose the right one for every task.

#### P.S.

A more optimized version of the `getDistinctDateFields` function consists of mapping first all records to the date field, and call `distinct()` right after. It eliminates the need to use the same `fieldGetter` instance twice :

```kotlin
private fun getDistinctDateFields(calendarField: Int)
    : suspend (List<Record>) -> List<Int> = { records ->
        records
            .asSequence()
            .map(newCalendarFieldGetter(calendarField))
            .distinct()
            .sorted()
            .toList()
    }
```

That being said, I won't modify the post to include this new version because it allows us to see the possibility of this kind of "function instance" use.