I use it quite often in places where I know it's safe to use, with the following import alias:
import kotlinx.coroutines.CoroutineStart.UNDISPATCHED as Undispatched
It'd be great to not have to have to add @UseExperimental(ExperimentalCoroutinesApi::class) to each usage.
I'm interested to know of any considerations that could justify leaving it experimental, postponing that decision or replacing it with something else (like a startDispatched: Boolean = true parameter).
As a work-around you can write in your project just once:
@UseExperimental(ExperimentalCoroutinesApi::class)
val Undispatched = kotlinx.coroutines.CoroutineStart.UNDISPATCHED
And then you will not have to add @UseExperimental at each use-site.
That's a great workaround. I'll add const.
You cannot add const, though.
Oh, that's right, it's not a primitive but an enum entry. I can make it inline instead.
We run into cases where we often want to initiate a concurrent process from a non-suspending context and ensure that we've run to a first suspension point to await incoming work. In compose this most recently has come up when we need to start a Recomposer before synchronously creating new compositions bound to it; if we can start the recomposition loop undispatched, we know we have not failed to observe any snapshot state invalidations that happened in between initial composition and the recomposition loop and associated snapshot observation beginning. Missing this window due to dispatch can mean we perform some initial composition work twice.
The shape of the use case reduces to something analogous to:
val channel = Channel<Data>()
coroutineScope.launch(start = CoroutineStart.UNDISPATCHED) {
for (item in channel) {
performWork(item)
}
}
channel.offer(dataItem) // should return true and submit dataItem to the already-receiving job
Note:
We've discussed internally and decided that the difference between Dispatchers.Unconfined and CoroutineStart.UNDISPATCHED (the latter does not form an event loop) is expected and advanced users (that know when they need UNDISPATCHED) know the difference and won't be surprised.
Most helpful comment
We run into cases where we often want to initiate a concurrent process from a non-suspending context and ensure that we've run to a first suspension point to await incoming work. In compose this most recently has come up when we need to start a Recomposer before synchronously creating new compositions bound to it; if we can start the recomposition loop undispatched, we know we have not failed to observe any snapshot state invalidations that happened in between initial composition and the recomposition loop and associated snapshot observation beginning. Missing this window due to dispatch can mean we perform some initial composition work twice.
The shape of the use case reduces to something analogous to: