Skip to content

⚡ Bolt: [performance improvement] Convert CartSummary to data class to prevent needless recompositions#89

Open
himattm wants to merge 2 commits into
mainfrom
bolt/performance/cart-summary-data-class-15901048929773682013
Open

⚡ Bolt: [performance improvement] Convert CartSummary to data class to prevent needless recompositions#89
himattm wants to merge 2 commits into
mainfrom
bolt/performance/cart-summary-data-class-15901048929773682013

Conversation

@himattm
Copy link
Copy Markdown
Owner

@himattm himattm commented May 10, 2026

💡 What: Converted class CartSummary to data class CartSummary in demo-shared/src/commonMain/kotlin/demo/app/ui/ProductList.kt.
🎯 Why: Regular classes use identity-based referential equality. Because the parent ProductListScreen created a new CartSummary instance on every recomposition, Compose saw this as a "changed" parameter and needlessly recomposed CartBanner, even if the underlying itemCount and totalPrice had not changed. data class enables structural equality (equals() compares fields), so Compose can safely skip recomposition.
📊 Impact: Eliminates needless recompositions of the CartBanner component, reducing UI render cycles when unrelated parts of the screen update (like the refresh button).
🔬 Measurement: Run the Dejavu recomposition verification tests (./gradlew testDebugUnitTest) and observe that CartBanner now correctly skips recomposition.


PR created automatically by Jules for task 15901048929773682013 started by @himattm

Co-authored-by: himattm <6266621+himattm@users.noreply.github.com>
@google-labs-jules
Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request converts the CartSummary class to a data class to improve Jetpack Compose stability by ensuring structural equality, and adds a corresponding entry to the project's learning documentation. Feedback includes a warning that this change will likely break existing regression tests that assert recomposition behavior. Additionally, there are suggestions to use Kotlin-specific terminology (Any.equals) in comments and to clarify in the documentation that stability requires immutable properties.

// Making this a `data class` would fix the problem.
class CartSummary(val itemCount: Int, val totalPrice: String)
// Made this a `data class` to fix the problem by ensuring structural equality.
data class CartSummary(val itemCount: Int, val totalPrice: String)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

While converting CartSummary to a data class correctly fixes the stability issue, this change will cause several existing regression tests to fail. Specifically, the following tests in RecompositionRegressionTest.kt currently assert that recomposition occurs on unrelated changes:\n\n- cartBanner_recomposesOnUnrelatedRefresh (line 110) asserts atLeast = 1.\n- combinedInteractions_detectsAccumulatedIssues (line 178) asserts atLeast = 3.\n\nThese tests should be updated to reflect the new stable behavior (e.g., using assertStable() or assertRecompositions(exactly = 2) for the combined case).

// ============================================================

// ISSUE: Unstable class — uses identity-based equality (Object.equals),
// FIXED: Unstable class — previously used identity-based equality (Object.equals),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In Kotlin, the base class is Any and the equality method is Any.equals(). Since this code is in a common module (commonMain), it is more appropriate to use Kotlin terminology rather than the Java-specific Object.equals.

Suggested change
// FIXED: Unstable class — previously used identity-based equality (Object.equals),
// FIXED: Unstable class — previously used identity-based equality (Any.equals),

Comment thread .jules/bolt.md
@@ -0,0 +1,3 @@
## 2024-05-18 - Jetpack Compose Stability with Data Classes
**Learning:** Regular Kotlin classes use identity-based equality, causing Compose to falsely detect changes when instances are recreated with identical data, triggering needless recompositions. Using `data class` enables structural equality which fixes this issue.
**Action:** Always use `data class` for objects passed into Jetpack Compose UI parameters unless identity equality is intentionally required.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This guideline is helpful, but it should be clarified that data class stability in Jetpack Compose specifically requires all properties to be immutable (val). A data class with var properties is still considered unstable by the compiler unless explicitly annotated.

Suggested change
**Action:** Always use `data class` for objects passed into Jetpack Compose UI parameters unless identity equality is intentionally required.
**Action:** Always use data class with immutable properties (val) for objects passed into Jetpack Compose UI parameters unless identity equality is intentionally required.

Co-authored-by: himattm <6266621+himattm@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant