Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 6

Function references in Kotlin

Function references are another of those great improvements that we get with Kotlin, which are
kind of exotic when we come from Java.

You already know that Kotlin supports functions as a type, what means that you can save a
function in a variable, use it as another function argument, or even make that a function returns
another function.

This is the main feature to consider that a language supports functional programming style, and
Kotlin of course allows this. You can declare a function in a variable like this:

val sum: (Int, Int) -> Int = { x, y -> x + y }

This is a function that receives two integers and returns one integer. In this particular
implementation, the lambda is applying an addition operation.

You could then have a function that accepts a lambda of this type as an argument:

fun applyOp(x: Int, y: Int, op: (Int, Int) -> Int): Int = op(x, y)

This is taking two integers and applying the function to both, so you can use the combination of
both this way:

applyOp(2, 3, sum)

Imagine that instead of a lambda, you have a plain function:

fun sum(x: Int, y: Int) = x + y

This is doing the same, but instead of having a variable that keeps the function, we just have a
function. Now, if you look at the call above, it is failing:

applyOp(2, 3, sum)

We need to use the function reference. For that, you only have to prepend two colons to the name
of the function:

applyOp(2, 3, ::sum)

a function reference behaves as a lambda, and as such, you can assign this reference to a variable
with the same structure:

val sumLambda: (Int, Int) -> Int = ::sum


How to Pass a Function as a Parameter to
Another in Kotlin?
Kotlin gives us the power to declare high-order functions. In a high-order function, we can pass
and return functions as parameters. This is an extremely useful feature and makes our code
much easier to work with. In Kotlin, we can declare functions and function references as values
that are then passed into the function.
Example

Let’s start by understanding how we declare functions as lambdas:

fun main () {
val funcMultiply = {a: Int, b: Int -> a*b}
println (funcMultiply (4, 3))
val funcSayHi = {name: String -> println ("Hi $name") }
funcSayHi("John")
}

So now that we have a general idea of how lambdas work, let’s try and pass one in another
function-that is, we will try a high-order function.
fun main () {
val funcMultiply : (Int, Int) ->Int = {a: Int, b:Int -> a*b}
val funcSum : (Int, Int) ->Int = {a: Int, b: Int -> a+b}
performMath (3, 4, funcMultiply)
performMath (3, 4, funcSum)
}

fun performMath (a: Int, b:Int, mathFunc : (Int, Int) -> Int) : Unit
{
println ("Value of calculation: ${mathFunc (a, b) }")
}

It is as simple as that-create a function lambda and pass it into the function. So this is just one aspect of
a high-order function-that is, we can pass a function as an argument to the function. Another use of
high-order functions is to return a function. Consider the following example where we need a function
that transforms the total price of an order according to certain conditions. Kind of like an e-commerce
site, but way simpler.

fun main() {
// free delivery of order above 499
val productPricel = 600;
// not eligible for free delivery
val productPrice2 = 300;
val totalCost1 = totalCost (productPrice1)
val totalCost2 = totalCost (productPrice2)
println("Total cost for item 1 is ${totalCost1 (productPrice1) }")
println ("Total cost for item 2 is ${totalCost2 (productPrice2) }")
}

fun totalCost (productCost : Int) : (Int) -> Int(


if (productCost > 499) {
return { x -> x }
}
else {
return { x -> x + 50 }
}
}

Note how we need to change functions that we apply based on certain conditions so that we
return a function that suits the conditions. We assign the returned function to a variable and then
we can just put append () in front of the variable to use it as a function, just like we did with the
lambdas. This works because the high-order function is essentially returning a lambda.

In Kotlin, we can assign a function to a variable, and then we can pass it into a function or return
it from a function. This is because it’s essentially declared like a variable. This is done using a
lambda declaration of functions.

Kotlin program of passing function which returns integer value-

// regular function definition


fun add(a: Int, b: Int): Int{
var sum = a + b
return sum
}
// higher-order function definition
fun higherfunc(addfunc:(Int,Int)-> Int){
// invoke regular function using local name
var result = addfunc(3,6)
print("The sum of two numbers is: $result")
}
fun main() {
// invoke higher-order function
higherfunc(::add)
}

Kotlin program of a function returning another function-

// function declaration
fun mul(a: Int, b: Int): Int{
return a*b
}
//higher-order function declaration
fun higherfunc() : ((Int,Int)-> Int){
return ::mul
}
fun main() {
// invoke function and store the returned function into a variable
val multiply = higherfunc()
// invokes the mul() function by passing arguments
val result = multiply(2,4)
println("The multiplication of two numbers is: $result")
}

Variable number of arguments (vararg) :


Kotlin
Sometimes we need a function where we can pass n number of parameters, and the value of n can be
decided at runtime. Kotlin provides us to achieve the same by defining a parameter of a function as
vararg. We can pass n number of parameters to a vararg variable of the defined datatype or even of a

generic type. A variable number of arguments (also known as varargs) is a feature of the Kotlin
language that allows you to pass a number of values as a single argument variable to a function.

When defining a function, you usually need to specify the name of each parameter that the function can
receive inside the function parentheses.

fun sumNumbers(a: Int, b: Int): Int {


return a + b
}

sumNumbers(2, 3) // 5

Now when you want to sum more numbers, you need to add another parameter to the function
definition.

The following example adds another parameter c to the sumNumbers function:

fun sumNumbers(a: Int, b: Int, c: Int): Int {


return a + b + c
}

sumNumbers(2, 3, 4)

One way of solving this problem might be to convert the numbers into an array.

That way, you can pass a single parameter of an IntArray type to the function and call the
sum() function rather than passing them one by one.

Consider the following code example:

fun sumNumbers(numbers: IntArray): Int {


return numbers.sum()
}

val numArray = intArrayOf(1, 2, 3, 4)

sumNumbers(numArray) // 1+2+3+4 = 10

A varargs is similar to how an array works. It allows you to pass a single variable that contains
multiple values. But when using a vararg, you don’t need to create an array. You can pass your
values separated by a comma, just like normal arguments.

To define a variable of arguments, you need to add the vararg keyword before the parameter
name as shown below:

fun sumNumbers(vararg numbers: Int): Int {


return numbers.sum()
}

sumNumbers(1, 2, 3, 4, 5) // 15

Notice how the vararg keyword is added before the numbers parameter and the values to sum
are passed just like regular arguments during the sumNumbers() call. This is the power of
varargs in Kotlin. It allows you to define a single variable as a function parameter that can
accept more than one value.

A vararg argument will be available inside the function as if it was an Array type data.

In the example above, you can call the same sum() function that’s available for IntArray type.

Here’s another example:


We need a function which takes n number as inputs and returns the average of all the inputs. If the size
of n variables is not fixed, we usually convert it into an array or list and pass it to function.

fun getAverage(numbersList: List): Float {

var sum = 0.0f


for (item in numbersList) {
sum += item
}
return (sum / numbersList.size)
}

val arrayList = arrayListOf(1, 2, 3, 4)


val result = getAverage(arrayList)
Now, what if the function itself takes n inputs and we don’t need to convert it into an array.

fun getAverage(vararg input: Int): Float {


var sum = 0.0f
for (item in input) {
sum += item
}
return (sum / input.size)
}
fun main(){
val result1 = getAverage(1, 2, 3)
val result2 = getAverage(1, 2, 3, 4, 5)
println(result1)
println(result2)
}

We can even pass all the elements of an array along with other arguments to a vararg variable. We can
use the spread (*) operator to do the same.

fun getAverage(vararg input: Int): Float {


var sum = 0.0f
for (item in input) {
sum += item
}
return (sum / input.size)
}
fun main() {
val array = intArrayOf(1, 2, 3, 4)
val result = getAverage(1, 2, 3, *array)
println(result)
}

You might also like