Kotlin: How to Do Higher-Order Functions

In this article, I want to show you from a beginner perspective how a programmer can implement higher-order functions in the beautiful language Kotlin! I tried to write my code snippets in a way that you can just copy and paste it in your preferred IDE and test it by yourself. And if you are already an expert you can take a look into my last example 😉

, Gally Tioman

In this article, I want to show you from a beginner perspective how a programmer can implement higher-order functions in the beautiful language Kotlin! I tried to write my code snippets in a way that you can just copy and paste it in your preferred IDE and test it by yourself. And if you are already an expert you can take a look into my last example 😉

Example 1: Basic Higher Order Function

In my first example I have a really basic higher-order function. The basicHigherOrderFunction now gets a function as parameter called myFunction with a Unit as a return value. You can identify the parameter by its type: () -> R . I can call myFunction inside the basicHigherOrderFunction like a normal function with the normal brackets./** My Higher-Order Function */ fun basicHigherOrderFunction(myFunction: () -> Unit) { println(“Start my Function!”) myFunction() // call my received parameter println(“Function finished”) }

If you now call the basicHigherOrderFunction in the main method it is possible to pass a function embedded in curly brackets to it like in the first method. But because it is Kotlin you could delete the normal brackets and only write the curly brackets for passing that function into basicHigherOrderFunction because it is the last parameter of the higher order function basicHigherOrderFunction like in the second method call.fun main() { basicHigherOrderFunction({ // inside normal brackets val result = 1 + 2 }) basicHigherOrderFunction { // only curly brackets val result = 1 + 2 } }

Example 2: Basic Higher Order Function with more parameters

In my next example I want to get a little bit more complicated: I only want to execute my function if the username equals a specific String./** My Higher-Order Function */ fun execute(username: String, myFunction: () -> Unit) { when(username) { “Arnold” -> myFunction() else -> throw NotAuthorizedException(“User is not authorized”) } }

If you take a look in my higher-order function execute(...) you can notify that I have now two parameters. The username and myFunction . On the caller side I can pass the username as a normal parameter inside the normal brackets and myFunction outside the function call in curly brackets. When I now execute my higher-order function I get a NotAuthorizedException with “User is not authorized” because my passed username is Lou. And my println("Print this if I am allowed") of that snippet is never executed.fun main() { execute(“Lou”) { println(“Print this if I am allowed”) } }

But you ask me if we can go crazy? Yes! Of course we can 😍

Example 3: Higher Order Function with its own Parameter

Now I want to use a function how everyone is using a function. With parameters! So I want to pass something to myFunction and I want to work with the parameter in my higher-order function./** My Higher-Order Function */ fun getRandomNumber(myFunction: Int.() -> Unit) { println(“Some really complex calculating…”) val myRandomNumber = Random.nextInt() println(“Passing result to myFunction()”) myFunction(myRandomNumber) }

You will now notice that the parameter declaration of myFunction  changed a little bit from () -> Unit to Int.() -> Unit because that Int in front of the . tells Kotlin that we need to pass an Int to myFunction . So what I am doing now is just getting a random Int from Kotlins default Random Class and passing it to myFunction . In the main function I just print my random Int by using it via this . Because this is the value I passed to myFunction inside the getRandomNumber.fun main() { getRandomNumber { println(“This is my random number: $this”) } }

But it is still possible to get more crazy! 🤓

Example 4: Higher Order Function with a return lambda

I will do it the other way around. I will calculate a random Int in my main where I call my higher-order function and want to print that random Int inside my higher-order function./** My Higher-Order Function */ fun printInt(myFunction: () -> Int) { println(“Passing result to myFunction()”) val myRandomNumber = myFunction() println(“This is my random Number $myRandomNumber”) }

You can notice now again that the declaration of myFunction parameter changed from Int.() -> Unit to () -> Int .
This means that our passed function myFunction has to return an Int instead of a Unit now.
When I call my printInt function in the main function, the last line of that function has to return an Int and will be taken as the return value for myFunction in my printInt and is printed there.fun main() { printInt { println(“Some really complex calculating…”) Random.nextInt() } }

But there is still a way to go much more crazy!! 😈 But first I want to talk about a keyword which may be useful if you are writing higher-order functions.

Inline keyword

When you have a simple higher-order function like in my first example, Kotlin will create an own object in the background for holding the function you wrote in the curly brackets just to pass it to your higher-order function. And if you are using your higher-order function f. e. in a while loop you will have a lot of objects only for holding your functions.

But Kotlin provides an easy solution for preventing that 🤘 You just have to write an inline in front of your function. But what does this change now?

The inline keyword copies the content of the inline function to the call side avoiding creating a new object for it.

So lets take a short look into my first example. Kotlin is creating a whole object for just holding val result = 1 2 . So I already would have 2 objects only for my lambdas 😱fun main() { basicHigherOrderFunction({ // inside normal brackets val result = 1 + 2 }) basicHigherOrderFunction { // only curly brackets val result = 1 + 2 } }

Because no one wants unnecessary objects you can write the inline keyword in front of my basicHigherOrderFunction . Let’s take a look what the Kotlin Compiler is now doing because it is a really nice improvement!fun main() { println(“Start my Function!”) val result = 1 + 2 println(“Function finished”) println(“Start my Function!”) val result1 = 1 + 2 println(“Function finished”) }

No object creation at all!!

You can see that the content of my higher-order function is copied inside the caller side.

So let us enter the last and craziest part here 🤖 The next part is for Kotlin experts!

Some generics and a where clause on function declaration?

If you write Kotlin you may have used the .ifEmpty { ... } function in Kotlin. And this function is exactly using that inline modifier and a higher order function! So let us take a look 😈public inline fun <C, R> C.ifEmpty(defaultValue: () -> R): R where C : Collection<*>, C : R { return if (isEmpty()) defaultValue() else this }

➡️  By looking at the inline modifier you can see that the content of ifEmpty is copied to the caller side for avoiding the creation of an object.

➡️  Then they declared two generics C and R and extended C with the .ifEmpty function.

➡️  Now they passed a higher order function called defaultValue which returns R and this is also the return type of ifEmpty . But when you once used this function you notice that if the Collection is not empty it can return the type of the Collection. But how does this now work?

➡️  Here comes the interesting part. In Kotlin you can specify a where clause after declaring the return value of a function. They specified that C has to be a Collection and C is also R . This is the trick 😊 With this trick it is possible to return a whole different type!

If you reached this part of my article I hope that there was something useful for you. Or it least something interesting.

Thank you for reading 🙂

General inquiries

We look forward to tackling your challenges together and discussing suitable solutions. Contact us - and get tailored solutions for your business. We look forward to your contact request!

Contact Us