I recently tried Compose Compiler Metrics and have...
# compose
t
I recently tried Compose Compiler Metrics and have a question regarding the Stability of Compose. Thanks for a very clear and simple tool! https://github.com/androidx/androidx/blob/androidx-main/compose/compiler/design/compiler-metrics.md Since Compose treats classes in another module as Unstable even if they are Immutable, if a class in another module has parameters in its arguments, even if the parameters have not changed, are they not skipped and subject to Recompose? I would like to know because it could considerably affect the design of the application using Compose. app module
Copy code
@Composable
fun Composable1(articles: Articles) {
  Text(text = "Hello $articles!")
}

@Stable
data class UiModel(val articles: Articles)

@Composable
fun Composable2(uiModel: UiModel) {
  Text(text = "Hello $uiModel!")
  uiModel.articles.articles.forEach {
    Composable3(it)
  }
}

@Composable
fun Composable3(article: Article) {
  Text(text = "Hello $article!")
}
model module
Copy code
data class Articles(val articles: List<Article>)
data class Article(val title: String)
app_release-composables.txt
Copy code
restartable fun Composable1(
  unstable articles: Articles
)
restartable skippable fun Composable2(
  stable uiModel: UiModel
)
restartable fun Composable3(
  unstable article: Article
)
source code https://github.com/takahirom/compose-multi-module-stability
r
I wonder why
data class Article(val title: String)
is unstable
1
Copy code
data class Articles(val articles: List<Article>)
This is unstable because
List
is
👍 1
a
You need to apply compose compiler plugin to model module in order for the stabilities of the classes defined there to be inferred.
s
^ yep, exactly that Stability only checks classes in the current module and relies on existing metadata for dependencies. If the metadata is not there, it will consider the class as unstable (unless it is a class from stdlib). To produce that metadata, you need to apply the compiler plugin to the module where classes are defined.
👍🏽 1
👍 1
m
Composable1 is not skippable because articles has unstable param(List). Composable2 is skippable UiModel is stable. Composable3 is not skippable because Article has unstable List
It would be nice if we could mark a param in a composable function as Stable, instead of having to create a wrapper
@Stable list: List<Int> !!
but i guess it doesn’t make that much sense, because we never know who will use that function. And marking it as Stable internally is kinda a recipe for disaster
t
Thanks for your advice! I applied Compose Compiler and runtime (required for build) to the model module. And now Composable1, Composable2 and Composable3 are all stable. In other words, in summary, if a module has a class that is passed as a Composable function argument, performance may be affected if the Compose Compiler is not adapted. - If you can apply the Compose Compiler to the module, then it is fine. - Otherwise, you need to wrap the class in a module with a
@Stable
class that has Compose's Compiler applied to it. https://github.com/takahirom/compose-multi-module-stability/commit/a4a1a34ec769a8524309a2205f43b8f28ce6e633#diff-14e800d090d55[…]dd4bae3552a9e209bL1
t
Found this thread from here. We are testing if an android library module that exposes models with stability annotations needs compose and compose compiler enabled. • Our lib module only depends on
androidx.compose.ui:ui:1.4.3
. Does not have compose
buildFeature
enabled/no compose compiler plugin ◦ We define
interface MutableData
with
@Immutable
annotation in this module • App module depends on this lib module. App module has compose/compose compiler
1.4.6
enabled • App module defines
_data class_ ViewState(_val_ a: Int, _val_ b: _MutableData_)
• Running Compose Compiler Metrics for release flavor in app module gives us this: With
@Immutable
on `interface MutableData`:
Copy code
stable class ViewState {
  stable val a: Int
  stable val b: MutableData
  <runtime stability> = Stable
}
Without
@Immutable
on `interface MutableData`:
Copy code
unstable class ViewState {
  stable val a: Int
  unstable val b: MutableData
  <runtime stability> = Unstable
}
Has something changed since this convo happened and the article was published? cc @takahirom since you wrote up the article (which is great btw, thank you for that!)
t
I saw a library that provides some annotations. I think we can use it for minimizing dependency. https://github.com/skydoves/compose-stable-marker