Manuel Wrage
01/22/2020, 2:21 PMChuck Jazdzewski [G]
01/22/2020, 5:57 PMequals(). For stable parameters the assumption is that we compare the previously passed values for all parameters and if equals() returns true then recomposition is unnecessary as the result will be the same as last time. This is certainly true for naturally immutable values, such as String and literals, but it is unclear for other data type. We use @Immutable so a developer can indicate that the values of a type should be treated as if they are immutable. @Stable can be used to indicate that, even though the type is not really immutable, it can be treated as one. For example @Model is marked with @StableMarker because it will invalidate the composition where it was read when it changes. We use @Stable when the type is not immutable but the changes cannot, or will not, be observed during composition. Modifier is the best example of this kind of type.
The main motivation for @Stable and @Immutable markers today is correctness of the generated code. It ensures we only assume we can skip composition when the types involved know, and are signed up for, the contract they are expected to obey.
In general, any object that can be mutated we should ignore the result of equals() for skipping, it will always be true even when the object has changed. Essentially we will be asking if a.equals(a) which should always be true. This doesn't tell us whether the composition will be the same for the value (as it won't be if the object is mutable and has changed) which is what we need to know for skipping. The exceptions for this are @Model or similar objects as composition observes changes in these objects, or Modifiers or similar objects where the mutations are not visible to composition (e.g. they are potentially updated with cached information during layout and draw) or object which are declared as mutable but generally are not (such as the result of deserialization from JSON or a protobuf).
We have considered inferring @Stable some cases that seem reasonable such as any data class that has only public val properties, and any enum class also with public val properties (if any). Both involve a risk as a binary compatible change can be made to either of these types that adds a var property which invalidates the code generation assumptions we have made for these types. In other words, even though the JVM and DEX consider these binary compatible changes, we would not.
As for the deserialization case we have some ideas along these lines but nothing concrete yet.