Introduction
Kotlin regards its functions as those of a first-class citizen. It enables the use of a function as a variable. A function, for example, can be supplied as an argument to another function, returned from another function, saved in a variable or data structure, and so on.
In this article, we will learn about Kotlin Higher-Order and Inline Functions and their need to use them. But before jumping into this, we would strongly recommend learning about Kotlin Lambda Expression.
Kotlin Higher-Order Function
In Kotlin, a higher-order function takes another function as an argument or returns another function. Lambda expressions are frequently supplied as arguments to or returned from higher-order functions. Kotlin Higher-Order Function can likewise use an anonymous function for this purpose.
We'll see a few examples of passing functions and lambdas as arguments or returning them from another function.
Function Types
We will study function types in Kotlin. A function type's syntax is as follows.
(Type, Type) -> ReturnType
With the parameter types on the left and the return type on the right. You can use the Unit for empty returns.
There are numerous ways to instantiate function types. Let's have a look at a few of them.
Lambda expressions
fun main() {
val evenOddCheck : (Int) -> Boolean = { it % 2 == 0 }
print(evenOddCheck.invoke(5))
}
Output:
false
It's worth noting that the evenOddCheck variable has an explicit type definition. Explicit Type Definition is optional if the compiler can deduce the type from the lambda expression. It is equal to
fun main() {
val evenOddCheck = { x : Int -> x % 2 == 0}
print(evenOddCheck.invoke(5))
}
Output:
false
This code will check if the provided number is even or odd. If you are wondering about the above code, it is a lambda expression that we have explained in this article.
Anonymous functions
Anonymous functions are declarations of functions that do not have a name. When the above evenOddCheck function is turned into an anonymous function, it looks like this.
fun main() {
val evenOddCheck = fun(x : Int) : Boolean = x % 2 == 0
print(evenOddCheck.invoke(5))
}
Output:
false
Some declaration types can be inferred, just like lambda expressions, simplifying your code.
Existing function
As an instance of a function type, member functions, top-level functions, or extension functions can be utilized. Obtaining a reference to the String, for example, using the reverse method which reverses the given string
fun main() {
val string = "abcdecda"
val reverse = String::reversed
print("Reverse of string $string is = " + reverse.invoke(string))
}
Output:
Reverse of string abcdecda is = adcedcba
Other function declarations, like constructors, are allowed.
Invoking function type instances
The syntax for launching function-type instances is relatively simple. You can use anyone.
f.invoke(x)
or simply
f(x)
Why does a function type have an invoke method? We have already explained this in Kotlin Lambda Expression.
Kotlin Function as an argument
The function printMessage() is supplied as an argument to higherOrderFunction() in this example, and it is called from the main() function
fun printMessage(name: String){
println("In printMessage() function")
println("Hi from $name")
}
fun higherOrderFunction(functionName: (name: String)-> Unit, name: String){
println("In higher order function")
println("Calling printMessage() function")
functionName(name)
}
fun main() {
higherOrderFunction(::printMessage, "Coding Ninjas")
}
Output:
In higher order function
Calling printMessage() function
In printMessage() function
Hi from Coding Ninjas
The function printMessage() prints two strings.
The function higherOrderFunction() accepts two arguments. The first parameter is a function, while the second is a string. The first function must be defined as a lambda expression in the argument. Let us look at its subparts:
- functionName is the name given to a function that is passed as an argument. So, from now on, we'll call the acceptable function (printMessage()) with functionName().
- Then we added (name: String), which reflects the printMessage() function's inputs.
- We mentioned the return type of the printMessage() method after ->.
We called functionName() (printMessage()) inside higherOrderFunction() and gave name as an argument.
The :: operator is used to pass a function as an argument. From main(), we called higherOrderFunction() and gave printMessage() as a parameter.
Kotlin Function as a return value
In this example, we shall return the printMessage() to higherOrderFunction().
fun printMessage(name: String) {
println("In printMessage() function")
println("Hi from $name")
}
fun higherOrderFunction(): (name: String) -> Unit {
println("In higher order function")
// return the printMessage function
return ::printMessage
}
fun main() {
val functionName = higherOrderFunction()
functionName("Coding Ninjas")
}
Output:
In higher order function
In printMessage() function
Hi from Coding Ninjas
The higherOrderFunction() is called in the main(), and the resulting value is kept in the functionName variable.
The return type is specified as (name:String) -> Unit in the higherOrderFunction(). It represents the printMessage() function's arguments and return type (which is the function to be returned).
The :: operator is used to return the printMessage() function. The returned function is saved in the variable functionName. It is called with functionName("Coding Ninjas"), which is the same as saying printMessage("Coding Ninjas").
Kotlin Lambda as an argument
Instead of a function, we pass or return a lambda expression most of the time. Let's look at the same examples we discussed before, but we'll use lambdas this time.
fun higherOrderFunction(functionName: (name: String)->Unit, name: String){
println("In higher order function")
println("Calling second function")
functionName(name)
}
fun main() {
higherOrderFunction({ name: String ->
println("Inside the lambda function")
println("Hi from $name")
}, "Coding Ninjas")
}
Output:
In higher order function
Calling second function
Inside the lambda function
Hi from Coding Ninjas
Instead of writing a separate function, printMessage(), and sending its name as a parameter, we created a lambda expression and directly sent it to our high order function. It operates in the same manner as described in the case of function as an argument.
Kotlin Lambda as a return value
Finally, consider the following case in which a function returns the lambda.
fun higherOrderFunction(): (name:String) -> Unit{
println("In higher order function")
return {name ->
println("Inside the lambda function")
println("Hi from $name")}
}
fun main() {
val functionName = higherOrderFunction()
functionName("Coding Ninjas")
}
Output:
In higher order function
Inside the lambda function
Hi from Coding Ninjas
Lambda Cost
You may already be aware of the hidden cost of utilizing lambda expressions now that you are aware that they are built as anonymous classes behind the hood.
There will be a class definition for each lambda expression that is defined. In addition, if your function is capturing, there will be an instance corresponding to the number of invocations. Fortunately, a feature called inlining can assist us with this.




