Higher Order Functions in Kotlin
- Higher-Order Functions in Kotlin
- Pass Function as a Parameter in Kotlin
- Kotlin Function as a Return Value
This tutorial teaches how to pass a function as a parameter and return a function using a function in Kotlin.
Functions in Kotlin are very flexible, and they can be stored in data structures, stored in variables, passed as an argument to a function, or returned by another function. They can do everything that the non-function variable does.
Higher-Order Functions in Kotlin
Higher-order functions in Kotlin are the functions that return a function or take a function as an argument or both. In other words, in Kotlin, you can have a function that takes another function as a parameter, return a function as a result, or does both, and these functions are called higher-order functions.
Let us see an example to see how it works.
fun main(){
fun hello() {
println("In hello!")
}
fun random(func : () -> Unit){
println("In random!")
println("calling hello")
func()
}
random(::hello)
}
Output:
In random!
calling hello
In hello!
Explanation:
-
Firstly, we have two other functions in the main function,
hello
andrandom
. -
hello()
takes no parameters and does not return any value (i.e., returnsUnit
). -
random()
takes one parameter, i.e., a function calledfunc
locally inrandom
’s scope and doesn’t return any value. Thefunc()
function doesn’t take any arguments and returns aUnit
, implying it doesn’t return a value.Therefore,
func
is a local name given to the function passed as a parameter while callingrandom
,:
(colon) is as usual written after the name of the variable to differentiate behavior and variable name, inside()
brackets parameters required by thefunc
function are written and after->
return type of the function is required. -
Lastly, we pass the
hello
function torandom
in the main method.
Let us see the output to understand the flow of the program.
First, as we call random
from the main
function passing hello
as an argument, we are inside the random
function. Thus we get the above two lines printed from the random.
Now random called func
, which is nothing but the hello
function as we passed it as an argument and thus in the last line, it is in the hello
function.
Lambda Expression in Kotlin
Lambda Expressions are function literals or anonymous functions in which we can write a function in a short and readable way. They also make the code look compact and clean.
For example:
val sum = {num1: Int , num2: Int -> num1 + num2}
The sum
takes two Int
variables, num1
and num2
, and returns an Int
num1+num2
(i.e., the sum of both numbers).
Pass Function as a Parameter in Kotlin
We can pass a function as a parameter to another function. Both these functions are free to have any return type and can have any number of data type parameters.
Also, the parameter functions can have no parameters and/or no return value.
Example 1:
Let us see an example of an Employee
class having two functions, years
that calculates the difference of years between two dates and print_details
that prints the employee details.
import java.time.LocalDate
// Employee class
public class Employee(id: Int, name: String, joining_date: LocalDate, leaving_date: LocalDate) {
var name: String = name
var id: Int = id
var joining_date: LocalDate = joining_date
var leaving_date: LocalDate = leaving_date
}
// function years returns difference between numbers of years of joining_date and leaving_date
fun years(date1 : LocalDate, date2 :LocalDate) : Int{
return date1.getYear()-date2.getYear()
}
// printing employee detains and years served to the company by the employee
fun print_details(emp: Employee, years: (LocalDate, LocalDate) -> Int) {
println(
"Employee ID: ${emp.id}\n" +
"Employee Name: ${emp.name}\n" +
"Years served: ${years(emp.leaving_date, emp.joining_date)}"
)
}
// main function
fun main(args: Array<String>) {
// object of Employee class
var Raghav = Employee(1004, "Raghav Mishra", LocalDate.parse("2005-09-30"), LocalDate.parse("2012-11-17"))
// printing detals
print_details(Raghav, ::years)
}
Output:
Employee ID: 1004
Employee Name: Raghav Mishra
Years served: 7
Employee
class objects have four parameters:name
,id
,joining_date
, andleaving_date
. Thejoining_date
andleaving_date
are of the data typeLocalDate
.- The
year
function takes twoLocalDate
variables. ThegetYear()
returns year in the particularLocalDate
and theyear
function returns the difference of the years in two dates asInt
. - The
print_details
takes an object of theEmployee
class and a function to calculate years of service by the employee. It printsEmployee ID
,Employee Name
, and years of service by passingjoining_date
andleaving_date
toyears
function. - In the main method, we create an object of the
Employee
class, and we call theprint_details
function by passing the employeeRaghav
and:: years
function that prints the details in the output.
::
operator (in this context) creates a callable reference to the function.Example 2:
To understand and apply this feature of Kotlin, let us take a more practical example for filtering a list.
fun main(args: Array<String>) {
var nums = listOf(153, 534,773,894,247,52)
fun odd(n : Int) : Boolean = n%2!=0
println("Odd numbers in the list are:")
nums.filter(::odd).forEach {n -> println(n)}
}
Output:
Odd numbers in the list are:
153
773
247
We take a list of numbers called nums
. Function odd
takes an Int
number as an argument and returns true
if the number is odd.
The filter
function takes a function as an argument which takes an element of nums
as a parameter and returns a Boolean. Here nums
is a list of Int
values; thus, odd
must take Int
as an argument and return a Boolean.
All the elements that result in true
in an odd
function are passed to (i.e., filtered) forEach
function. The forEach()
function takes a Lambda expression or a function as a parameter and returns a Unit
, printing each number to a new line.
Note:
nums.filter(::odd).forEach {n -> println(n)}
The above code can also be written like below to get the same results.
nums.filter(::odd).forEach(::println)
//or
nums.filter{ odd(it) }.forEach { println(it) }
//or
nums.filter{odd(it)}.forEach(::println)
The it
can be replaced by some other name like in a Lambda function: nums.filter{n -> odd(n)}
Thus to sum up: forEach{n -> println(n)}
== forEach{println(it)}
== forEach(::println)
Kotlin Function as a Return Value
Higher-order functions are also the functions that return another function. Again returned function can have a return value or return a Unit
and take no or any number of parameters.
Let us see an example of a calculator, where we take user input of 2 numbers and give the user a choice of how to operate these numbers, and finally return the result.
We will take two functions, and the first one returns a function as per the choice given by the user. The second function takes the function returned by the first function and operates.
// add func
fun add(a: Int, b: Int) : Int = a+b
// sub func
fun subtract(a: Int, b: Int) : Int = a-b
// multiply func
fun multiply(a: Int, b: Int) : Int {return a*b}
// division func
fun divide(a: Int, b: Int) : Int {return a/b}
// incorrect input
fun error(a: Int, b: Int) : Int {
println("error");
return -1
}
// choose returns a function requested by the user
fun choose(choice : Int) : (a : Int, b : Int)-> Int{
return when(choice){
1 -> ::add
2 -> ::subtract
3 -> ::multiply
4 -> ::divide
else -> ::error
}
}
// function returning a function
fun perform(a : Int, b : Int, action : (a : Int, b : Int)-> Int) : Int{
return action(a,b)
}
fun main(){
println("Enter first number")
var a = Integer.parseInt(readLine())
println("Enter second number")
var b = Integer.parseInt(readLine())
println("Enter choice:\n1 add\n2 subtract\n3 multiply\n4 divide")
var choice = Integer.parseInt(readLine())
var result = perform(a,b,choose(choice))
println("Result = $result")
}
Output:
Enter the first number
8493
Enter the second number
3
Enter choice:
1 add
2 subtract
3 multiply
4 divide
4
Result = 2831
In the main function, we ask the user for 2 numbers first and then ask for choice. In the choice
method, we pass the user’s choice.
The choice
function returns a function as selected by the user. Therefore, we have created five functions: add
, sub
, multiply
, divide
, and error
.
One of these is returned by the choice
function. This function is then passed to the perform
function, it takes two numbers of Int
type, and a function returned by the choice
function say func
.
Two user-entered numbers are passed to func
, and the result returned by func
is printed as output.
Also, note that the add
and sub
are initialized with the =
(equal to) sign. The multiply
and divide
are initialized with {}
.
Both are correct and can be used but add
and sub
is simpler to understand.
Pass Lambda Expression Instead of Function in Kotlin
In Kotlin, we can pass a Lambda expression instead of a function if we have to use the function only once and the function is a one-line expression. Say, for instance, instead of passing the divide
function; we choose to pass the expression directly to perform the function as below.
var res = perform(a,b, { a,b -> a/b })
Niyati is a Technical Content Writer and an engineering student. She has written more than 50 published articles on Data Structures, Algorithms, Git, DBMS, and Programming Languages like Python, C/C++, Java, CSS, HTML, KOTLIN, JavaScript, etc. that are very easy-to-understand and visualize.
LinkedIn