I have a base UseCase class:
abstract class UseCase<RESULT> internal constructor(private val executionDispatcher: CoroutineDispatcher,
private val postExecutionDispatcher: CoroutineDispatcher)
: CoroutineScope {
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = executionDispatcher + job
fun dispose() {
job.cancel()
}
//---
suspend operator fun invoke(): RESULT {
return suspendCoroutine { continuation ->
launch(executionDispatcher) {
try {
val result = run()
launch(postExecutionDispatcher) {
continuation.resume(result)
}
} catch (e: Exception) {
launch(postExecutionDispatcher) {
continuation.resumeWithException(e)
}
}
}
}
}
internal abstract fun run(): RESULT
}
that:
- uses suspended function
invoke()
and executesrun()
on executionDispatcher but return/throw on postExecutionDispatcher - extends
CoroutineScope
so therefore has possibility to be cancelled
When running code inspection on this class I get (on invoke()
):
Ambiguous coroutineContext due to CoroutineScope receiver of suspend function
Detailed explanation:
This inspection reports calls & accesses of CoroutineScope extensions or members inside suspend functions with CoroutineScope receiver. Both suspend functions and CoroutineScope members & extensions have access to coroutineContext. When some function is simultaneously suspend and has CoroutineScope receiver, it has ambiguous access to CoroutineContext: first via kotlin.coroutines.coroutineContext and second via CoroutineScope.coroutineContext, and two these contexts are different in general case. So when we call some CoroutineScope extension or access coroutineContext from such a function, it’s unclear which from these two context do we have in mind. Normal ways to fix this are to wrap suspicious call inside coroutineScope { … } or to get rid of CoroutineScope function receive
The issue is caused by launch()
methods inside my suspened function.
Is there a way to write that function in a different way but still meet requirements for UseCase class?