min
07/23/2026, 9:19 AMcompositionLocalWithComputedDefaultOf. I’ve read the code a little, and it seems that .provides(T): ProvidedValue<T> returns one where compute = null, isDynamic = true which means
val local = compositionLocalWithComputedDefaultOf {/* ... */}
CompositionLocalProvider(local provides x) {/* ... */}
The CompositionLocalProvider will remember a DynamicValueHolder for it at that position in the composition like it does for locals constructed by compositionLocalOf, which means they’re backed by mutable states and their readers are recomposed on invalidation. Once you’ve explicitly provided a value, there’s no difference between a local by compositionLocalWithComputedDefaultOf and compositionLocalOf. So when do I use it and why?min
07/23/2026, 9:29 AMval key = compositionLocalOf<String> {/* ... */}
CompositionLocalProvider(key provides "value") {
val nested = compositionLocalWithComputedDefaultOf { key.currentValue }
}
Upon further investigation, I see that nested cannot be created by compositionLocalOf. How does compositionLocalWithComputedDefaultOf make that work though?min
07/23/2026, 10:15 AMsomeLocal.current when a value hasn’t been provided calls
1. currentComposer.consume(this) where this = someLocal
2. this.currentCompositionLocalScope().read(key) where this = currentComposer
3. this.getOrElse(key as CompositionLocal<Any?>) { key.defaultValueHolder }.readValue(this) as T where this is the return value of currentCompositionLocalScope
4. map.compute() in readValue where map is its parameter, and this is the return value of getOrElse which is a ComputedValueHolder<T>(val compute: CompositionLocalAccessorScope.() -> T) in the case of a compositionLocalWithComputedDefaultOf local
Why did this have to be a separate ProvidableCompositionLocal subtype though? Why couldn’t this be enabled in compositionLocalOf?shikasd
07/24/2026, 2:03 AMmin
07/24/2026, 8:35 AMdefaultFactory parameter type is CompositionLocalAccessorScope.() -> T in compositionLocalWithComputedDefaultOf<T>? Why couldn’t it have been @Composable () -> T?
// If `defaultFactory: @Composable () -> T`
// In `compositionLocalWithComputedDefaultOf<T>`
val key = compositionLocalWithComputedDefaultOf { someCompLocal.current }
What problem does CompositionLocalAccessorScope.() -> T solve that @Composable () -> T would not have?shikasd
07/24/2026, 8:36 AMmin
07/24/2026, 11:09 AMComposition locals can be read outside of composition@shikasd Really? The docs don’t even allude to that fact, so that’s quite disconcerting, but I massively appreciate your clarification.
public object LocalViewModelStoreOwner {
private val LocalViewModelStoreOwner =
compositionLocalWithHostDefaultOf(ViewModelStoreOwnerHostDefaultKey)
public val current: ViewModelStoreOwner?
@Composable get() = LocalViewModelStoreOwner.current
public infix fun provides(
viewModelStoreOwner: ViewModelStoreOwner
): ProvidedValue<ViewModelStoreOwner?> {
return LocalViewModelStoreOwner.provides(viewModelStoreOwner)
}
}
Could you also explain why it wraps a ProvidableCompositionLocal<ViewModelStoreOwner?> to manually reimplement its instance members please? A wrapper typically exists to intercept and mediate access, but this object relays everything as-is.shikasd
07/24/2026, 1:27 PMmin
07/25/2026, 7:18 AMclass MyModifier: Modifier.Node(), CompositionLocalConsumerModifierNode {
companion object {
val LocalKey = compositionLocalOf { 0 }
}
override fun onAttach() {
Log.d("MY_MODIFIER",
@SuppressLint("SuspiciousCompositionLocalModifierRead")
this.currentValueOf(MyModifier.LocalKey).toString()
)
}
}
Also LocalViewModelStoreOwner is not a viewmodel. It’s an object in androidx.lifecycle.viewmodel.compose.efemoney
07/25/2026, 9:42 AMasSharedFlow() API to wrap a MutableSharedFlow so that the underlying object type is not mutable, is the same way the ProvidableCompositionLocal needs to be encapsulated so that its not mutable outside of the internal library.min
07/25/2026, 6:07 PMefemoney
07/25/2026, 8:06 PMmin
07/27/2026, 8:47 AMChuck Jazdzewski [G]
07/30/2026, 8:56 PMval local = compositionLocalWithComputedDefaultOf {/* ... */}
CompositionLocalProvider(local provides x) {/* ... */}
In this example there is no difference between using compositionLocalOf() and compositionLocalWithComputedDefaultOf()
Where the two diverges is what happens when you don't provide local, what is the value of local? If a compositionLocalOf() composition local is not provided defaultValue is invoked (the first time, it is cached after that) and is returned as value. In compositionLocalWithComputedDefaultOf() the compute lambda is called every time but it is also a `CompositionLocalAccessorScope`so it can read other composition locals to produce its value.
An example of this use is, assume you have a holder of values (think Context in Android) but you want to surface parts of the holder as separate composition locals (such as default text direction). Before computed composition locals, you were required to provide each local separately. Now you can declare the individual holders as computed by default which will read the holder and return the value. Then providing a new holder all the individual locals will now report values from the new holder without requiring their being explicitly re-provided.min
07/31/2026, 8:00 AMLocalViewModelStoreOwner is a wrapper? It doesn’t prevent or enable anything. I wonder if this is vibecoded.Chuck Jazdzewski [G]
07/31/2026, 9:31 PMmin
08/01/2026, 10:19 AMLocalViewModelStoreOwner was a bare CompositionLocal<ViewModelStoreOwner?>