Higher Order Functions in Kotlin

Pranav Jayaraj
6 min readSep 20, 2020

Now, before we look at higher order function let’s begin with an example to make things clear enough. Let’s say I have a requirement to capture a view in android as an image, apply some filters to the image, store it to the device and share it with any one. Below are the basic steps involved to achieve the same

I . I will need to refer the view and create a bitmap from it

2. Apply some complex filters

3. Store the bitmap to the device.

4. Fetch the image from location and share the image

I want to do this process of applying filter in a different thread instead of the UI thread since it might block the UI thread, we don’t want to hurt our poor UI thread don’t we? So I am using Rx to do the image generation process in a different thread. You can do it via other methods like Coroutines or Async task etc.

I am going to use the following function to get the job done

private fun getImage(view: View) {
val image = view.drawToBitmap()
ApplyFiltersAndStoreImage(
mContext,
"Example.jpg",
image)
.subscribeOn(schedulers.Computation()) // computation thread
.observeOn(schedulers.ui())
.subscribe({
shareImage(it) // function which shares the image
}, {
}
).addTo(disposables)
}

But now let’s say I met with another requirement to do the same process but Instead of sharing the image I need to show a notification displaying the generated image.

Now there are multiple ways to handle this situation,

  1. I could write the same image generation function twice to perform different actions.
  2. I could use the same function and rather than writing it twice I could pass the type of action it should perform after image is generated i.e apply conditions on the type to check whether to share the image or to display the image as a notification.

But the problem with above solution is what if I come up with more such requirement now I want the same function to generate image and upload the image to server.

For method 1 there is going to be redundancy of code.

For method 2 well things will become messy and non atomic. We will have to write many conditions in the same function. I don’t need to explain the necessity of writing clean code do I ?

Maybe we could also use live data to post the value once it is generated and then put some logic to handle the execution too. But that would turn out to be complex.

So how to write clean code, make the functions atomic and reduce redundancy in the above case ? How can we write an elegant solution for this problem ?

Well the answer is Higher Order Functions.

What are Higher Order Functions ?

“A function which can accept a function as parameter or can return a function is called Higher-Order function”

We can create smaller functions that only take care of one piece of logic. Then, we compose more complex functions by using different smaller functions.

A basic higher Order function syntax takes the below form.

fun higherOrderFunc(block: () -> Unit) 
{
block() //invokes the expression
}

We can either pass lambda expression or an anonymous function as parameter to the higher functions. In Kotlin it is preferred to use lambda expression since it is convenient.You can get detailed explanations on lambda functions on the internet but I will give a quick syntax brush up to speed things up if you are not familiar.

Lambda functions

Below is the basic Lambda syntax

a) val sum = { x:Int, y:Int -> println(x + y) } // without optional paramsb) val sum: (Int, Int) -> Unit = { x: Int, y: Int -> println(x + y)} // with optional params

Note: Both the above lambda functions are same except one has optional params and the other does not.

When you call sum(2,3) it will print 5

If we want to return the addition then change the return type from Unit to Int and the last line will be treated as the return value.

Now we are going to solve the problem we faced using the higher order function we just learned. Lets see how.

Here we are going to use the ability of higher order function to accept function as its parameter and returning a Unit to solve our problem. Now we will pass the lambda expression which we just learned instead of a named function to the higher order function.

Passing lambda expression as a parameter to Higher-Order Function which returns a Unit

Note: We can also pass the expression by putting it within the curly braces of the caller function as show below in functionA. i.e only the view is passed directly into the function and the expression is passed within the curly braces. What if we simply create a lambda function and pass it? We will need to create separate lambda functions for each action which we need to execute and it will be messy and confusing. Both the below code does the same stuff. where getImage is the higher order function.

Method 1

private fun functionA(view: View) {
getImage(view)
{location->
//do your stuff
}
}

Method 2

private fun functionA(view: View) {
getImage(view, actionOne) // actionOne is our lambda function
}
val actionOne = {it:String->
// do your stuff
}

we will be using the method 1 for our solution, let’s get back to solving

private fun functionA(view: View) {
getImage(view)
{location->
ShareImage(location)
}
}

private fun functionB(view: View) {
getImage(view)
{location->
openNotification(location)
}
}
private fun functionC(view: View) {
getImage(view)
{location->
sendImageToServer(location)
}
}
private fun getImage(view: View, block: (it: String) -> Unit) {
val image= view.drawToBitmap()
ApplyFiltersAndStore(
mContext,
"example.jpg",
image
)
.subscribeOn(schedulers.Computation())
.observeOn(schedulers.ui())
.subscribe({
block.invoke(it) // or block(it)
}, {

}
).addTo(disposables)
}

Lets look at the above code, shall we?

I have three functions Function A, Function B & Function C

Function A will share the image to another app. Function B will open the image via notification and Function C will send the image to server. But we can also see there is another function getImage() which is being used by all the above three functions. This function is known as the higher order function

Now lets analyse the getImage() higher order function.

private fun getImage(view: View, block: (it: String) -> Unit) {
val image= view.drawToBitmap()
ApplyFiltersAndStore(
mContext,
"example.jpg",
image
)
.subscribeOn(schedulers.Computation())
.observeOn(schedulers.ui())
.subscribe({
block.invoke(it)
}, {

}
).addTo(disposables)
}

Understanding the above code,

block: (it: String) -> Unit 

This line of code accepts a function as its value, which we learned when we went through the basics of higher order functions.

i.e whatever is written within those curly braces of the higher order function will get executed as if those things were written in a separate function and then called separately. In this case { location->ShareImage(location) } is the line of code which is taken as a function which is invoked by the higher order function getImage() when we call block.invoke(location)

block.invoke(it)

funcName.invoke() or funcName() when written will immediately invoke the expression which is passed as parameter in the higher order function. Now lets move forward.

The generated location is then passed through the block function to the below expression i.e location-> and then shareImage is executed which makes use of the location to get the image from device location and share it.

{location->
ShareImage(location)
}

Next we will be looking at certain optimisations which we can apply while using Higher Order Functions and that I will be covering in another article. Until then.

--

--

Pranav Jayaraj

Android Engineer with 4+ years working for early stage product startups