Consider the following race condition:
void onButtonClicked() {
launch(uiEventLoop) {
disableButton()
doWork.await()
enableButton()
}
}
The problem is that disableButton() is first posted to the event loop before executed and the user could click the button again in the meantime. This means doWork could run twice in parallel what is probably unintended. The solution is to call disableButton() before launching the coroutine to prevent another click. However, this is a subtle problem which many devs would probably not notice or ignore. Furthermore, the disable/enable part would be in two different code blocks and can’t be automated using extension functions…
I wonder if it would make sense to add special dispatchers that run the first part of the coroutine in the current thread. For example, a JavaFXEventHandler dispatcher that runs the first dispatch call in the current thread (only if it is indeed the java fx thread). Or to include this behaviour on default for UI dispatchers.
Or add a helper (simplified):
class StartNow(val parent: CoroutineDispatcher) : CoroutineDispatcher() {
private var first = true
override fun dispatch(context: CoroutineContext, block: Runnable) {
if (first) {
first = false
block.run()
} else
parent.dispatch(context, block)
}
}