How is the paramter onScreenChange : (String) -> Unit passed to the function body : @Composable ((String) -> Unit) -> Unit?

The Code A is from the main branch of the official sample project.

There are three subclass Overview, Accounts and Bills of the enum class RallyScreen in the project.

There is a function fun content(onScreenChange: (String) -> Unit) { body(onScreenChange) } which accept the paramater onScreenChange : (String) -> Unit in the class RallyScreen.

Although the statement is enum class RallyScreen(val body: @Composable ((String) -> Unit) -> Unit) {..}, the body = { OverviewBody() } in the class Overview, the body = { AccountsBody(UserData.accounts) } in the class Accounts and the body = { BillsBody(UserData.bills) } in the class Bills don't require to pass the paramter (String) -> Unit), why can Kotlin run well and navigate by Tab well when the App launch fun content(onScreenChange: (String) -> Unit) { body(onScreenChange)} ?

Code A

@Composable
fun RallyApp() {
    RallyTheme {
        val allScreens = RallyScreen.values().toList()
        var currentScreen by rememberSaveable { mutableStateOf(RallyScreen.Overview) }
        Scaffold(
            topBar = {
                RallyTabRow(
                    allScreens = allScreens,
                    onTabSelected = { screen -> currentScreen = screen },
                    currentScreen = currentScreen
                )
            }
        ) { innerPadding ->
            Box(Modifier.padding(innerPadding)) {
                currentScreen.content(
                    onScreenChange = { screen ->
                        currentScreen = RallyScreen.valueOf(screen)
                    }
                )
            }
        }
    }
}


enum class RallyScreen(
    val icon: ImageVector,
    val body: @Composable ((String) -> Unit) -> Unit
) {
    Overview(
        icon = Icons.Filled.PieChart,
        body = { OverviewBody() }  
    ),
    Accounts(
        icon = Icons.Filled.AttachMoney,
        body = { AccountsBody(UserData.accounts) } 
    ),
    Bills(
        icon = Icons.Filled.MoneyOff,
        body = { BillsBody(UserData.bills) } 
    );

    @Composable
    fun content(onScreenChange: (String) -> Unit) {
        body(onScreenChange)
    } 
}


@Composable
fun OverviewBody(
    onClickSeeAllAccounts: () -> Unit = {},
    onClickSeeAllBills: () -> Unit = {},
    onAccountClick: (String) -> Unit = {},
) {
   ...
}

@Composable
fun AccountsBody(
    accounts: List<Account>,
    onAccountClick: (String) -> Unit = {},
) {
    ...
}

@Composable
fun BillsBody(bills: List<Bill>) {
    ...
}

Added Content:

To Gabriel Pizarro: Thanks!

By the statement of clas Overview, the body needn't any parameter, it use default values, how is the onScreenChange parameter passed ?

Overview(
   icon = Icons.Filled.PieChart,
   body = { OverviewBody() }  //It needn't any parameter
)


@Composable
fun content(onScreenChange: (String) -> Unit) {
   body(onScreenChange)
} 

And more, the app can work well when I add two default parameters for fun OverviewBody(...) .

@Composable
fun OverviewBody(
    onClickSeeAllAccounts: () -> Unit = {},
    onClickSeeAllBills: () -> Unit = {},
    a1: (String) -> Unit = {},              // I add
    onAccountClick: (String) -> Unit = {},
    a2: (String) -> Unit = {},              //I add
) {
   ...
}

Maybe body = { OverviewBody() } should be body = { OverviewBody(onAccountClick = it) } in Overview class, right?

Actually, NO!!!

The lambda that body receives is different from OverviewBody.onAccountClick. In body's lambda, the String refers to a name of RallyScreen as you can see from its usage here. And in onAccountClick lambda, the String represents an accountName.

By the statement of class Overview, the body needn't any parameter, it use default values, how is the onScreenChange parameter passed ?

onScreenChange is not passed called anywhere and that's why navigation doesn't work.

You can make the SEE ALL buttons in Overview screen work using:

Overview(
    icon = Icons.Filled.PieChart,
    body = { 
        OverviewBody(
            onClickSeeAllAccounts = { it(Accounts.name) },
            onClickSeeAllBills = { it(Bills.name) },
        ) 
    }
)

The onAccountClick lambda in OverviewBody is tricky to handle. We need to show the SingleAccountBody composable when AccountRow is clicked. Right now there is no RallyScreen corresponding to that composable. So you will have to create a new enum value in RallyScreen something like this:

Overview(
    icon = Icons.Filled.PieChart,
    body = {
        OverviewBody(
            onClickSeeAllAccounts = { it(Accounts.name) },
            onClickSeeAllBills = { it(Bills.name) },
            onAccountClick = { accountName ->                   >>>>>>
                it(SingleAccount.name)                                |   
            }                                                         |
        )                                                             | 
    }                                                                 |
),                                                                    |
Accounts(                                                             |
    icon = Icons.Filled.AttachMoney,                                  | 
    body = {                                                          | 
        AccountsBody(UserData.accounts)                               |
    }                                                                 |
),                                                                    |
Bills(                                                                |
    icon = Icons.Filled.MoneyOff,                                     |
    body = { BillsBody(UserData.bills) }                              |
),                                                                    | 
SingleAccount(                                                        |
    icon = Icons.Filled.AttachMoney,                                  | 
    body = {                                                          |
        SingleAccountBody(UserData.getAccount(???accountName???)) <<<--
    }
);

Here we need to send that accountName received from Overview screen to SingleAccount screen to make the navigation work. But there is no simple way to do that with the current code structure and I don't want to complicate this answer much. In the final code of this codelab, this accountName has been passed using NavArguments.