Kotlin — Function as a parameter
It’s fun when you can pass the fun into another fun as a parameter. Ow, fun means function :p . Every function in kotlin is a fun. And it’s really fun!
Do you know what’s happing in this following code?
fun add(a: Int, b: Int): Int = a + b
fun increment(a: Int): Int = a + 1fun calc(a: Int, b: Int, perform: (a: Int, b: Int) -> Int) = perform(a, b)
fun calc(a: Int, perform: (a: Int) -> Int) = perform(a)fun useFunctionAsParameter() {
val result = calc(1, 2, ::add)
val result2 = calc(result, ::increment) Log.e(TAG, "1 + 2 = $result")
Log.e(TAG, "$result + 1 = $result2")
}
If you know then great! If not and you are interested about whats going on here then let’s explore more!
Recently I had do some works with a large codebase. For simplicity we were dividing the functions into smaller functions. Then somehow I faced the situation of calling different functions is going to need a bit more repeating code. Like, calling different functions in different confirmation dialog. Although the dialog is almost same but the functions I was calling after confirmation is a bit different. I came up with the idea of using a common interface with a common dialog for all. But, still it is a bit of code too and same code for every call. Then I went to the 2nd idea of passing the functions also. It was great and less of code. I did some searching and study also. Let’s share:
The simplest example:
This is the function we are going to pass as a parameter. The simplest one:
fun passMeAsParameter() {
Log.d(TAG, "I am the parameter function bro.")
}
This is the function where we will pass our function:
fun passAFunctionToMe(parameterFunction: () -> Unit) {
parameterFunction()
}
And finally this is how we use it:
fun useFunctionAsParameter() {
passAFunctionToMe(
{passMeAsParameter()}
)
}
Not that hard huh! In the last function we passed the passMeAsParameter() function as a function parameter. See the second braces. They are necessary. But looks like a bit..um..not so hot. Here lambda comes in handy.
fun useFunctionAsParameter() {
passAFunctionToMe {passMeAsParameter()}
}
There is another cooler way to do this:
fun useFunctionAsParameter() {
passAFunctionToMe(::passMeAsParameter)
}
Yap. Just two colons(::) makes it more fun!
Okay let’s make it a bit harder. This time we will write a whole function as a parameter.
fun useFunctionAsParameter() {
passAFunctionToMe(
{Log.d(TAG, "I am the parameter function bro.")}
)
}
Simple, isn’t it! Now, how about passing a parameter in the parameter function!
//function to pass
fun passMeAsParameter(log: String) {
Log.d(TAG, log)
}//function with a function as a parameter
fun passAFunctionToMe(parameterFunction: () -> Unit) {
parameterFunction()
}//now use the parameter function
fun useFunctionAsParameter() {
val log = "I am the parameter function bro.""
passAFunctionToMe(
{parameterFunction(log)}
)
}
With lambda:
passAFunctionToMe {passMeAsParameter(log)}
A bit more complex version with more fun:
//function to pass
fun passMeAsParameter(log: String) {
Log.d(TAG, "This is a $log")
}//function with a String and a function as parameter
fun passAFunctionToMe(log: String, parameterFunction: (log: String) -> Unit) {
parameterFunction(log)
}//now use the parameter function
fun useFunctionAsParameter() {
val log = "nice log""
passAFunctionToMe(
log, {parameterFunction(log)}
)
}
We don’t want to write same parameter twice. Let’s do this:
passAFunctionToMe(
log, {parameterFunction(it)}
)
Yes, you are right. “it” means that “log” will go there. With lambda it will be more beautiful:
passAFunctionToMe (log) {passMeAsParameter(it)}
But we don’t want to write “it” too.
passAFunctionToMe(
passAFunctionToMe (log, ::passMeAsParameter)
)
Again just two colons(::) makes it more fun!
Now let’s say, the function which we want to pass as parameter is in another class. No problem at all:
//another class
class AnotherClass {
//function to pass
fun passMeAsParameter() {
Log.d(TAG, "I am the parameter function bro.")
}
}class MainClass {
//function with a function as a parameter
fun passAFunctionToMe(parameterFunction: () -> Unit) {
parameterFunction()
} //now use the parameter function
fun useFunctionAsParameter() { val anotherClass = AnotherClass()
passAFunctionToMe(anotherClass::passMeAsParameter)
}
}
Want to pass more than one function? Okay
//function with unlimited functions as parameter(Using vararg)
fun passManyFunctionsToMe(vararg functions: () -> Unit) {
functions.forEach { function -> function() }
}//now use the parameter function
fun useFunctionAsParameter() {
passManyFunctionsToMe(::function1, ::function2, ::function3, ...)
}
Here I used vararg. You can use arrays, list or anything you want.
Your function has a return type? No problem:
fun add(a: Int, b: Int): Int {
return a + b
}fun calc(a: Int, b: Int, perform: (a: Int, b: Int) -> Int): Int {
return perform(a, b)
}
fun useFunctionAsParameter() {
val result = calc (1, 2, { x: Int, y: Int -> add(x, y)}) Log.e(TAG, "1 + 2 = $result")
}
A more simpler (and b-e-a-uuuu-tiful) version of this code is:
fun add(a: Int, b: Int): Int = a + b
fun calc(a: Int, b: Int, perform: (a: Int, b: Int) -> Int) = perform(a, b)
fun useFunctionAsParameter() {
val result = calc(1, 2, ::add) Log.e(TAG, "1 + 2 = $result")
}
That’s it! Now you know how to use function as a parameter. You will now also understand the code snipped we we were looking at the beginning of the tutorial. Kotlin is a very powerful language with many many awesome features. There are Coroutines, Android Extensions and many more! For now have fun with fun!