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 🙂