Kotlin Tutorial

Kotin Higher Order Functions (With Examples)

Table of Contents

  • Introduction
  • What is Higher Order Function in Kotlin?
  • Characteristics of Kotlin Higher Order Functions
  • Example of Higher Order Function in Kotlin
  • Passing Lambda Expression as Parameter to Higher-Order Function
  • Kotlin Program of Lambda expression, Which Returns Unit
  • Passing Function as Parameter to Higher-Order function
  • Returning a function from a Higher-Order function
  • Important Concepts

Introduction

In Kotlin, functions are considered first-class citizens. This programming language allows the use of functions as variables. For example, we can supply a function as an argument to another function, save in a data structure, return from another function, and more. 

In this blog, let’s discuss more about higher order function in Kotlin, their uses, examples, and more.

What is Higher Order Function in Kotlin?

A higher-order function in Kotlin is a function that can accept other functions as arguments and/or return functions as results. This concept is a fundamental part of functional programming and provides a powerful mechanism for abstracting and manipulating behavior in your code. Higher-order functions are a key feature in Kotlin and enable more concise and expressive programming.

Characteristics of Kotlin Higher Order Functions

Here are the key characteristics of higher-order functions in Kotlin:

  • Accepting Functions as Arguments 

Higher-order functions can take other functions (lambdas or function references) as parameters. These functions can be invoked within the higher-order function.

  • Returning Functions

Higher-order functions can return functions as results. These returned functions can be used later or passed to other functions.

  • Lambda Expressions 

Higher-order functions are often used with lambda expressions to specify the behavior you want to pass as an argument.

  • Function Types

Higher-order functions typically have function types as their parameter types or return types. Function types describe the signature of the functions that can be accepted or returned.

Example of Higher Order Function in Kotlin

Let’s understand the Kotlin higher-order functions with examples:

Example 1

Here's an example of a simple higher-order function:

fun operateOnNumbers(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
    return operation(a, b)
}

In this example, operateOnNumbers is a higher-order function that accepts two integers (a and b) and a function (operation) of type (Int, Int) -> Int as its parameters. You can pass different operations as lambdas when calling this function, such as addition or multiplication.

Example 2

Here, we'll create a higher-order function that performs an operation on a list of numbers based on a passed lambda expression:

fun operateOnNumbers(numbers: List<Int>, operation: (Int) -> Int): List<Int> {
    return numbers.map { operation(it) }
}
fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    // Define a lambda function to double a number
    val doubleOperation: (Int) -> Int = { x -> x * 2 }
    // Use the higher-order function to double each number in the list
    val doubledNumbers = operateOnNumbers(numbers, doubleOperation)
    println("Original numbers: $numbers")
    println("Doubled numbers: $doubledNumbers")
}

In this example:

The operateOnNumbers function is a higher-order function that takes a list of integers (numbers) and a lambda (operation) as parameters. The lambda takes an integer and returns an integer.

Inside the operateOnNumbers function, we use the map function to apply the provided operation to each element in the numbers list.

In the main function, we define a lambda (doubleOperation) that doubles a number. We then call the operateOnNumbers function with the list of numbers and the doubleOperation lambda to double each number in the list.

Output:

Original numbers: [1, 2, 3, 4, 5]
Doubled numbers: [2, 4, 6, 8, 10]

Passing Lambda Expression as Parameter to Higher-Order Function

Passing a lambda expression as a parameter to a higher-order function is a common use case in Kotlin. It allows you to pass behavior as data, making your code more flexible and expressive. 

Here's an example of how to pass a lambda expression as a parameter to a higher-order function:

fun operateOnNumbers(numbers: List<Int>, operation: (Int) -> Int): List<Int> {
    return numbers.map { operation(it) }
}
fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    // Pass a lambda expression to double the numbers
    val doubledNumbers = operateOnNumbers(numbers) { x -> x * 2 }
    // Pass a lambda expression to square the numbers
    val squaredNumbers = operateOnNumbers(numbers) { x -> x * x }
    println("Original numbers: $numbers")
    println("Doubled numbers: $doubledNumbers")
    println("Squared numbers: $squaredNumbers")
}

In this example:

The operateOnNumbers function is a higher-order function that accepts a list of integers (numbers) and a lambda (operation) as parameters. The lambda takes an integer and returns an integer.

In the main function, we call the operateOnNumbers function twice. We pass lambda expressions as arguments to specify the behavior we want. The first call doubles each number in the list, and the second call squares each number.

Output:

Original numbers: [1, 2, 3, 4, 5]
Doubled numbers: [2, 4, 6, 8, 10]
Squared numbers: [1, 4, 9, 16, 25]

Kotlin Program of Lambda expression, Which Returns Unit

In Kotlin, lambda expressions can return Unit explicitly. Unit is similar to void in other programming languages and is used to indicate that a lambda doesn't return a meaningful value. 

Here's an example of a lambda expression that explicitly returns Unit:

val doSomething: () -> Unit = {
    println("This lambda returns Unit.")
}
fun main() {
    doSomething()
}

In this example:

doSomething is a lambda expression with no parameters and a return type of Unit. The lambda doesn't return a value; instead, it simply prints a message when called.

In the main function, we call the doSomething lambda, and it prints the specified message.

Output:

This lambda returns Unit.

Passing Function as Parameter to Higher-Order function

You can pass a function as a parameter to a higher-order function in Kotlin. This allows you to abstract and parameterize behavior, making your code more flexible and expressive. 

Here's an example of how to pass a function as a parameter to a higher-order function:

fun operateOnNumbers(numbers: List<Int>, operation: (Int, Int) -> Int): List<Int> {
    val result = mutableListOf<Int>()
    for (i in 0 until numbers.size step 2) {
        if (i + 1 < numbers.size) {
            result.add(operation(numbers[i], numbers[i + 1]))
        } else {
            result.add(numbers[i])
        }
    }
    return result
}
fun add(a: Int, b: Int): Int {
    return a + b
}
fun subtract(a: Int, b: Int): Int {
    return a - b
}
fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    val addedNumbers = operateOnNumbers(numbers, ::add)
    val subtractedNumbers = operateOnNumbers(numbers, ::subtract)
    println("Original numbers: $numbers")
    println("Added numbers: $addedNumbers")
    println("Subtracted numbers: $subtractedNumbers")
}

In this example:

The operateOnNumbers function is a higher-order function that accepts a list of integers (numbers) and a function (operation) of type (Int, Int) -> Int as a parameter. It processes the numbers in pairs using the operation function and returns a list of results.

The add and subtract functions are regular functions that match the signature of (Int, Int) -> Int. These functions perform addition and subtraction operations, respectively.

In the main function, we call the operateOnNumbers function twice, passing the add and subtract functions as the operation parameter. This allows us to add and subtract numbers from the list based on the selected operation.

Output:

Original numbers: [1, 2, 3, 4, 5]
Added numbers: [3, 7, 5]
Subtracted numbers: [-1, -1, 5]

Returning a function from a Higher-Order function

You can return a function from a higher-order function in Kotlin. This allows you to create functions on the fly based on certain conditions or inputs. 

Here's an example of how to return a function from a higher-order function:

fun getOperation(type: String): (Int, Int) -> Int {
    return when (type) {
        "add" -> { a, b -> a + b }
        "subtract" -> { a, b -> a - b }
        "multiply" -> { a, b -> a * b }
        "divide" -> { a, b -> a / b }
        else -> { _, _ -> 0 } // Default operation (returns 0)
    }
}
fun main() {
    val addition = getOperation("add")
    val subtraction = getOperation("subtract")
    val multiplication = getOperation("multiply")
    val division = getOperation("divide")
    val unknownOperation = getOperation("unknown")
    println("Addition: ${addition(5, 3)}") // Output: Addition: 8
    println("Subtraction: ${subtraction(5, 3)}") // Output: Subtraction: 2
    println("Multiplication: ${multiplication(5, 3)}") // Output: Multiplication: 15
    println("Division: ${division(6, 2)}") // Output: Division: 3
    println("Unknown operation: ${unknownOperation(5, 3)}") // Output: Unknown operation: 0
}

In this example:

The getOperation function is a higher-order function that takes a type as a parameter and returns a function of type (Int, Int) -> Int. Depending on the type parameter, it returns a specific operation function (addition, subtraction, multiplication, division), or a default operation that returns 0 for an unknown type.

In the main function, we call getOperation with different operation types to get the corresponding functions. Then, we use these functions to perform the specified operations on numbers.

When you run the code, it will output the results of the different operations based on the functions returned by the getOperation higher-order function.

Important Concepts

  • Function Types

Now, let’s learn about function types in Kotlin.

Syntax of the Function Type

(Type, Type) -> ReturnType

We mention the parameter type on the left and the return type on the right and use the Unit for empty returns.

  • Anonymous Functions

Anonymous functions don’t have a name. When we turn an evenOddCheck function into an anonymous function, it looks like the following:

Example 

fun main() {
   val evenOddCheck = fun(x : Int) : Boolean = x % 2 == 0
   print(evenOddCheck.invoke(5))
}
Output
false
  • Existing function

We can use member functions, extension functions, or top-level functions as an instance of a function type. For example, obtaining a reference to the String using the reverse method, reversing a string's values.

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, such as constructors, are also allowed.

  • Invoking function type instances

There are two syntaxes to launch function-type instances, and both of them are simple. You can use either.

f.invoke(x)

or

f(x)
Did you find this article helpful?