One Off the Slack: Why Do We Need SideEffect?

Florian Walther asked:

Even tho I read the documentation, I can’t wrap my head around why we need to use SideEffect here. The functionality works without the SideEffect call. Can someone tell me why we need it? https://google.github.io/accompanist/systemuicontroller/

The code in question is from the current Accompanist documentation for its system UI controller support:

// Remember a SystemUiController
val systemUiController = rememberSystemUiController()
val useDarkIcons = MaterialTheme.colors.isLight

SideEffect {
    // Update all of the system bar colors to be transparent, and use
    // dark icons if we're in light theme
    systemUiController.setSystemBarsColor(
        color = Color.Transparent,
        darkIcons = useDarkIcons
    )

    // setStatusBarsColor() and setNavigationBarsColor() also exist
}

Google’s Adam Powell attempted to explain:

Composition is a transaction. Anything you do in a @Composable function shouldn’t have observable side effects until after that transaction commits successfully. SideEffect {} does this, deferring its block of code until the composition transaction that scheduled it is successful.

SideEffect is also guaranteed to run that code on the applier thread (e.g. the Android UI thread) whereas composition itself may run on a background thread in the future

If composition fails, then nothing in that composition transaction is meant to have ever happened. By using SideEffect you can meet this contract. Otherwise you would need to ensure yourself that no mutations you make are visible externally before composition succeeds.

In this case, the system UI (e.g., status bar) is not even in our app, let alone in our composition. Anything that we do to it from a composable is, by definition, a side effect of that composable and should be handled via SideEffect (or perhaps some other type of Effect).

Florian seemed unconvinced:

So the difference is that without SideEffect the call to setSytemBarsColor would execute if the Composable was canceled for some reason?

but in reality it would probably not make any observable difference, is that correct?

Adam focused on correctness:

Writing wrong code that works by luck will generally come back to bite you eventually 🙂


Read the original thread in the kotlinlang Slack workspace. Not a member? Join that Slack workspace here!