In Kotlin, functions are the first class citizens. A function can be passed as an argument to another function, return it as a value from other functions, and assign it to a variable or data structure. To facilitate this, Kotlin uses specialized constructs to represent a function. In this article we will learn how we can use functions just like any other expressions in Kotlin.

Higher Order function

Higher order functions can take a function as an argument or return a function as a value or do both. 

fun add(first: Int, second: Int, sum: (Int, Int) -> Int) {
    println(sum(first, second))
}

fun sumOfTwoNumbers(a: Int, b: Int): Int = a + b

fun main(args: Array<String>) {
    add(2, 3, ::sumOfTwoNumbers)
}

In this example, the function add is a higher order function because its last parameter sum is a function. The function type of sum specified in the signature of add() is quite unusual isn’t it? Let’s break down what it means.

Fig. 2: Function types syntax

This means that the function sum has two arguments of type Int and returns a value that is an Int. To pass a function as a parameter to another function, we have used :: before the function name as shown in line 8.

Rules of function Type

We have seen how a function type looks like in fig. 2. Let’s see some more variations of it.

  • To represent a function that takes multiple arguments and has a return type, we would declare it as. 
  • To represent a function type with empty arguments, we would use something like:
  • To representing a function with no return type, we would use the following:

Instantiating Function Type

In fig 1, we have used a callable reference to an existing function i.e ::sumOfTwoNumbers to represent a function passed as a value for the parameter sum

Alternatively, we could also directly pass the code block. We can achieve that in two different forms – lambda expression and anonymous function.

A lambda expression

An example of a Lambda expression is shown below.

Line 8 in fig. 1 can be replaced with

An anonymous function

An example of an anonymous function is shown below.

Line 8 in fig. 1 can be replaced with

Lambda expression and anonymous function are the function literals which means they are a function that is not declared but directly passed as an expression. The above-mentioned lambda and anonymous functions are equivalent to a regular function as shown below.

Lambda Expression syntax

A lambda can be defined as follows

Fig. 3: Lambda syntax

A lambda expression is enclosed inside the curly braces. The parameters declaration and the body are present inside the braces separated by -> symbol.

If the return type of the lambda expression is not Unit then the last expression inside the body is considered as a return value.

Passing trailing Lambdas

If the last parameter of a function is a lambda expression, then it can be written outside the parentheses. The following two examples are equivalent.

If the lambda expression has only one parameter then we do not have to have a parameter list inside the lambda, instead, we can use it to refer to the parameter.

fun printElements(value: Int, p: (Int) -> Unit) {
    p(value)
}

fun main(args: Array<String>) {
    printElements(2) { println(it) }
}

Anonymous Function

Let’s look at the lambda expression in fig. 3, the data type of the parameters passed is specified however the return type is not explicitly mentioned. Most of the time, the return type can be inferred automatically however sometimes we might need to specify explicitly, in that case, we can use anonymous functions.

Anonymous functions look very similar to the regular functions except that the function name is omitted. 

The data type of the parameters can also be omitted. The return type can be inferred when the function body is an expression otherwise should be mentioned explicitly.

There is a difference between Anonymous function and lambdas while working with the return statement. In an anonymous function, the return statement inside the function block would return from the anonymous function, whereas the return statement inside the block of lambda would return from the enclosing function.

Storing functions in a variable or data structure

In Kotlin, the function like anonymous functions or lambda function can be stored to a variable just like any other value.

fun add(first: Int, second: Int, sum: (Int, Int) -> Int) {
    println(sum(first, second))
}

val sum: (Int, Int) -> Int = { a, b ->
    println("Operand1 = $a Operand2 = $ b")
    a + b
}

fun main(args: Array<String>) {
    add(2, 3, sum)
}

In this example the lambda is assigned to a variable sum and the variable sum can be used in the same way as any other variables.

Higher order functions make the life of a programmer easier as we can write a small expressive function that is less prone to bugs and is easy to test. Those small functions can then be combined to perform complex operations.

Thank you for taking the time to read the articles. Please let us know if there is any specific topic you would like to read about.

Category
Tags

One response

Leave a Reply

Your email address will not be published. Required fields are marked *