https://kotlinlang.org logo
#compose
Title
# compose
j

jeff

12/14/2021, 10:43 PM
Hoping someone can help me understand this recomposition behavior:
Copy code
class Helper {
  val string = "string"
}

@Composable
fun RecompRepro(mutableState: MutableState<String>, helper: Helper) {
  LogCompositions(msg = "Root")
  Column(Modifier.height(100.dp)) {
    Text(mutableState.value)
    CustomComposableText(helper = helper)
  }
}

@Composable
fun CustomComposableText(helper: Helper) {
  LogCompositions(msg = "CustomComposableText")
  Text(helper.string)
}
if I change the value of mutableState 3 times, "Root" is printed 3 times and "CustomComposableText" is printed 1 time. That is as expected. But if I change
val string
to
var string
in
Helper
, then all of a sudden CustomComposableText is printed 3 times. Why?
same effect if I add an unrelated and unreferenced
var
to
Helper
-- it feels like it's automagically determining whether my Helper class is immutable or something...?
i

Ian Lake

12/15/2021, 12:14 AM
The docs talk about how Compose infers stability (and how the
@Stable
annotation can be used to indicate that a type truly is stable): https://developer.android.com/jetpack/compose/lifecycle#skipping
j

jeff

12/15/2021, 2:09 AM
That makes sense I think, thank you for the link. I guess I'm not clear on the specifics of
Compose considers a type stable only if it can prove it.
It seems to be able to "prove" that my class is stable if it only has
val
s, even ones like
Copy code
val int get() = Random.nextInt()
which seems decidedly not-stable.
I guess I'm just surprised that on one hand Compose is doing things like analyzing the call stack to tell if you indirectly reference a property through any means, and on the other hand assuming that val/var can tell you whether a property is stable. Maybe I'm overthinking this...
i

Ian Lake

12/15/2021, 4:07 AM
I'd report a bug if a non-data class with a val with
get()
is inferred as stable (as it shouldn't)
It is doing a lot more than looking at val or var
This is my current understanding, is it about right? When Compose is recomposing, and is trying to decide whether a given recompose scope can be skipped: 1. Are any of the inputs unstable? -> can't skip 2. If all of the inputs are stable, have any of them changed (via .equals())? -> can't skip 3. else, (i.e. all of the inputs are stable, and are .equals() to their previous value) -> CAN skip where "inputs" includes actual function parameters but also any external thing the body of the function references?