Table of contents
1.
Introduction
2.
Kotlin Higher-Order Function
2.1.
Function Types
2.1.1.
Lambda expressions
2.1.2.
Anonymous functions
2.1.3.
Existing function
2.1.4.
Invoking function type instances
2.2.
Kotlin Function as an argument
2.3.
Kotlin Function as a return value
2.4.
Kotlin Lambda as an argument
2.5.
Kotlin Lambda as a return value
2.6.
Lambda Cost
3.
Kotlin Inline Function
4.
FAQs
5.
Key Takeaways
Last Updated: Mar 27, 2024

Kotlin Higher-Order and Inline Function

Author Rahul Sain
1 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

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.

Kotlin Inline Function

Inline functions enable us to save memory during runtime and improve our program's efficiency.

We've already talked about lambda expressions and higher-order functions. Let us continue with the same example.

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 lambda function")
       println("Hi from $name")
   }, "Coding Ninjas")
}

 

Output:

In higher order function
Calling second function
Inside lambda function
Hi from Coding Ninjas

 

We can produce the bytecode for our Kotlin program in IntelliJ. To do so, navigate to Tools > Kotlin > Show Kotlin Bytecode. We can decompile this bytecode and produce Java code from it.

We will see that a new Function object is produced for the lambda expression. But this was not what we had hoped for.

Each higher-order function will build a new object and assign it to memory. It will increase the amount of time spent running. We use inline functions to solve this problem.

We can use the inline keyword to prevent creating a new object for each higher-level function. It will aid us in improving the code's performance. Instead of generating a new object for a higher-order function, the inline keyword replicates the code within the inline function to the location from where it is called.

Before the fun keyword, the inline keyword is inserted.

inline 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 lambda function")
       println("Hi from $name")
   }, "Coding Ninjas")
}

 

Output:

In higher order function
Calling second function
Inside lambda function
Hi from Coding Ninjas

 

If you are adding the inline keyword before a standard function, it does not affect performance. Intellij will also recommend that you delete it.

Remember that the inline keyword should only be used when the higher-order function is brief. If a higher-order function contains a large amount of code, the produced code will be extremely long.

Must Read Elvis Operator Kotlin

FAQs

  1. Why they are called higher order functions?
    It is called higher-order since it operates on functions rather than Strings, Integers, or Booleans.
     
  2. When should we use Inline Function in Kotlin?
    When all functional type parameters are called directly or provided to another inline function, you can use Inline. When a function argument is assigned to a variable within the function, you cannot use Inline.
     
  3. What is the difference between a callback and Higher-Order Function?
    A higher-order function accepts another function as a parameter and returns it to its callers. A callback function is supplied to another function with the expectation that the other function will call it.

Key Takeaways

Cheers if you reached here!! 

The purpose of this article was to introduce you to the Kotlin Higher-Order and Inline Function, the basic syntax of implementing this and understand the basic core concept about Higher-Order and Inline Function in Android Development.

If you want to learn more about Arrays in Kotlin, you can jump to this article which covers them in great detail.

However, learning never stops, and there is more to learn. So head over to our Android Development Course on the Coding Ninjas Website to dive deep into Android Development and build future applications. Till then, Happy Learning!

Live masterclass