Lesson 3
Composition storage is runtime memory
Separate groups and slots used for recomposition from the UI tree they help update.
Status: The storage/tree distinction is Durable . The selected buffer and class names are Version-specific at the pinned revision. The link-buffer path is Experimental at this revision.
Outcome
You should be able to answer this question precisely:
If composition storage is not the UI tree, what job does it do?
It keeps the runtime’s memory of composition structure and values so later work can compare, restart, skip, and update the right places.
Storage remembers composition structure
A composable body can call remember, read state, and conditionally emit content. Later, the body may run again. The runtime needs more than the latest node tree to decide what the new execution means.
It records composition information such as:
- groups and their nesting;
- slots containing remembered values or other group data;
- anchors that help identify positions across edits; and
- invalidation scopes associated with observed reads.
These records support recomposition. They are runtime memory, not rendered objects.
flowchart LR
Composer[Composer calls] --> Storage[Groups and slots]
Storage --> Compare[Compare later execution]
Compare --> Recompose[Recomposition work]
Storage --> Memory[Runtime memory]
Memory -->|not the target tree| Nodes[UI nodes]The last edge is a boundary, not a data flow. Storage helps decide node changes. It does not become the node tree.
The pinned runtime has more than one storage path
At the pinned revision, CompositionImpl creates its internal slotStorage through a flag. The default path uses the gap-buffer composer. The link-buffer composer is selected only when ComposeRuntimeFlags.isLinkBufferComposerEnabled is true (Composition.kt, slotStorage and createSlotStorage).
That yields two safe statements:
- The runtime needs structured composition storage. Durable
- This revision’s default selection and buffer implementations are versioned. Version-specific
The link-buffer path is Experimental here. Do not teach it as a settled replacement for the gap buffer. A flag, source revision, and release note are part of the claim.
Why the distinction matters
Suppose a state read invalidates a restart scope. The runtime uses composition memory to locate the work that may need to run again. It can then calculate an update to an existing node.
The stored group is not the node. The remembered value is not the node. The anchor is not a node address in the target tree.
This is why two diagrams can both be true:
- Composition storage tracks logical execution and remembered data.
- An applier separately owns a target tree.
Confusing them makes every later explanation harder. A slot-table change is not automatically a layout-tree change. A node move is not automatically a slot move.
A small inspection exercise
Open the pinned Composition.kt and find slotStorage.
Then answer:
- What does the surrounding documentation say the storage is for?
- Which flag selects the link-buffer path?
- Which separate interface owns target-tree operations?
The third answer is Applier.kt, not a slot-table class.
Misconception check
“The slot table is Compose’s rendered tree.”
A better statement is: the slot storage is composition memory; the applier owns a target-specific tree. The two cooperate, but they have different owners and different operations.
Source notes
| Claim | Direct evidence | Status |
|---|---|---|
slotStorage stores composition information needed for recomposition | Composition.kt | Durable
Version-specific |
| Gap and link composers are selectable implementations | Composition.kt, GapComposer.kt, and LinkComposer.kt | Version-specific
Experimental |
| The target tree is a separate applier concern | Applier.kt | Durable |
Freshness
Refresh this lesson when CompositionImpl.createSlotStorage, the default flag, or the composer implementations change. Check current Compose Runtime release notes before describing the link-buffer path as anything more than Experimental
.
Finished this lesson?
Your progress stays only in this browser.