Checking that a coroutinescope uses the correct dispatcher

As a followup to this thread, I’d like to know if it is possible to check what dispatcher a coroutinescope (or rather, its associated context) uses.

I know that the coroutine context contains the job and the dispatcher associated with the coroutine. What I don’t know is how to access the context dispatcher. Ideally, I could do something like require(context.dispatcher == expectedDispatcher). Is this possible?

You can acquire a coroutine dispatcher with coroutineContext[ContinuationInterceptor]. Then you can compare it to existing dispatchers, check its type, etc.:

withContext(Dispatchers.IO) {
    val dispatcher = coroutineContext[ContinuationInterceptor]!!
    println("Dispatchers.Default: ${dispatcher == Dispatchers.Default}") // false
    println("Dispatchers.IO: ${dispatcher == Dispatchers.IO}") // true
}

However, it sounds like a bad idea. You should not need to know what is the current dispatcher. If you need some specific dispatcher then just switch to it.

Also, there are probably much more dispatcher implementations than standard: Main, Default, IO and Unconfined and they aren’t part of the public API. So if you need to check whether the current dispatcher is based on Java executors then I think you can only do this by referencing internal stuff.

As said, this is essentially a continuation of the last thread. I want to check that the scope does not use a dispatcher that could run tasks in parallel. My library’s public API functions use withContext(singleThreadedDispatcher) {} internally to ensure that parallelization is prevented. However, it would be good to be able to check that this still holds true in internal functions, and that I didn’t accidentally somehow inherited the wrong dispatcher. This could help catch errors that would otherwise be difficult to pinpoint later on. I agree that in general the dispatcher should not be accessed like that, but for purposes of debugging and robustness, I think it makes sense.

By the way, if I use withContext(dispatcher) in a scope that already uses the same dispatcher, is this withContext a no-op, or does this still consume some resources? I think it is a no-op, but I can’t find the location in the docs where I think I saw that mentioned.