Passing a Function from a Parent to a Child Composable

What are parameters and arguments?

Michihiro Iwasaki
5 min readOct 24, 2023

·Function that Has a Parameter of a Function

Before diving into Jetpack Compose, let’s ensure we understand functions in Kotlin by using some simple examples. In particular, if you’re unfamiliar with the concept of “passing a function as an argument to another function,” it might be best to start with the basics.

A function is like a package that groups various processes. Once you declare a function, you can call it anytime and from anywhere.

However, if you want to do more various processes flexibly, you will need to set parameters on a function.

For example, this function below always returns 3 (result of 1 + 2), so it isn’t a useful function.

fun plusNumber(): Int {
return 1 + 2
}

println(plusNumber()) // 3

By setting parameters to receive integers, you can freely adjust the numbers being added.

fun plusNumber(x: Int, y: Int): Int {
return x + y
}

println(plusNumber(x = 3, y = 2)) // 5

However, this sample is still very simple.

If you want to do more complex processes, you will have to set a parameter that receives a function.

For example, there is a function that returns a result of double an argument like below:

fun doubleNumber(x: Int): Int {
return x * 2
}

println(doubleNumber(3)) // 6

And then, assuming that you want to declare a function that returns strings like “Double the ○○ is ××” using this function, you have to set a parameter that can receive a function.

doubleNumber() is a function that receives Int and returns Int, so the parameter that can receive this function is like below:

fun printDoubleNumberMessage(doubleNumFun: (Int) -> Int) {

}

In addition, to determine what integer doubles, it is necessary to set the second parameter that receives Int.

fun printDoubleNumberMessage(doubleNumFun: (Int) -> Int, num: Int) {

}

And then, to get the result of strings, it needs to set a return value as String.

fun printDoubleNumberMessage(doubleNumFun: (Int) -> Int, num: Int): String {
return "Strings"
}

Finally, adjust the returned string as you want, using the provided arguments.

fun printDoubleNumberMessage(doubleNumFun: (Int) -> Int, num: Int): String {
return "Double the $num is ${doubleNumFun(num)}"
}

println(
printDoubleNumberMessage(::doubleNumber,3) // Double the 3 is 6
)

If you want to pass a function, which has been assigned to a variable (or a constant) using a lambda, to another function, here’s a sample code:

val doubleNumber = { x: Int ->
x * 2
}
fun printDoubleNumberMessage(doubleNumFun: (Int) -> Int, num: Int): String {
return "Double the $num is ${doubleNumFun(num)}"
}
println(
printDoubleNumberMessage(doubleNumber,3) // Double the 3 is 6
)

Additionally, you can directly pass the function as an anonymous function using lambda.

...
println(
printDoubleNumberMessage( { it * 2 }, 3 ) // Double the 3 is 6
)

Grasping these fundamental concepts in Kotlin is crucial before diving into Jetpack Compose.

➔Next, I’ll demonstrate how to pass a function from a parent Composable to a child Composable in Jetpack Compose.

·Pass a Function from Parent Composable to Child Composable

When working with Jetpack Compose, you’ll frequently need to pass data from a parent Composable to its child.

Imagine a system that displays the game result, such as “Your score is ○○!”, when a button is tapped.

In this scenario, both the score (an Int) and the boolean determining whether the score is displayed are managed by the parent Composable. And then, a button is placed by the child Composable.

This situation image is below:

In such a situation, passing both the Int and Boolean values to the child Composable can be cumbersome. Additionally, there’s a risk of unintentionally overwriting these values in the child Composable.

In this scenario, you only need to pass a function to the child Composable that “changes the value of the Boolean”. Therefore, you must set a parameter in the child Composable to receive this function.

Therefore, a simple example of passing a function from a parent Composable to a child Composable is as follows:

@Composable
fun ParentComposable(
modifier: Modifier = Modifier
) {
val gameResult = 80
var isShowResult by remember {
mutableStateOf(false)
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = modifier
) {
Text(text = "Your score is…")
if(isShowResult) {
Text(text = "$gameResult !!")
} else {
// Insert something as needed
}
Spacer(modifier = Modifier.height(36.dp))
ChildComposable(onButtonClick = {isShowResult = true})
}
}
@Composable
fun ChildComposable(
onButtonClick: () -> Unit
) {
Button(onClick = onButtonClick) {
Text(text = "Show Result")
}
}

In this example, the function passed from the parent to the child Composable neither requires arguments nor returns anything. Hence, the child Composable’s parameter is set as () -> Unit.

With this approach, there’s no need to pass the values of gameResult(Int) or isShowResult(Boolean).

In Jetpack Compose, you’ll encounter code unrelated to function passing. While this might seem challenging, its structure remains consistent with the basics introduced earlier.

The process simply involves setting a parameter to receive a function (on the child Composable’s side) and passing the function as an argument (on the parent Composable’s side).

Once you grasp these basics, you’ll find it easier to navigate various Composables in Jetpack Compose. Initially, using Jetpack Compose felt enigmatic to me. However, as I became familiar with the basics, it started to feel more intuitive.

If you ever feel overwhelmed while using frameworks like Jetpack Compose, returning to the fundamentals of programming can be a helpful strategy!

<aside>
<p>
Thank you for reading!<br>
If you enjoyed this post, I'd appreciate a clap. 😄
</p>
</aside>

--

--