Description
With Kotlin coroutines there is a convention to declare functions starting a coroutine and return immediatly as extension function on CoroutineScope
.
And there is also a language keyword “suspend” to tell the opposite: that the function may not resume immediatly, and may suspend a coroutine without blocking.
Therefore writing a suspend
extension function on CoroutineScope
is very confusing for the reader: Does it resume immediatly or not?
Snippet of non-compliant code
suspend fun CoroutineScope.doSomething() {
val part1 = async { computePart1() }
val part2 = async { computePart2() }
return combine(part1.await(), part2.await())
}
Snippet of compliant code (fixing the above noncompliant code)
Let it suspend and remove CoroutineScope receiver from the signature
suspend fun doSomething() = coroutineScope {
val part1 = async { computePart1() }
val part2 = async { computePart2() }
combine(part1.await(), part2.await())
}
Or let the CoroutineScope receiver from the signature and remove the suspend modifier
fun CoroutineScope.doSomething() {
launch {
val part1 = async { computePart1() }
val part2 = async { computePart2() }
println(combine(part1.await(), part2.await()))
}
}
External references
The maintener of kotlinx.coroutines, Roman Elizarov, wrote a good article about it here: https://medium.com/@elizarov/explicit-concurrency-67a8e8fd9b25
Type: Code Smell
It confuse the reader and makes harder to understand if it launches coroutines or if it suspend.
I would personally set the default severity to “Major”
Tags:
multi-threading, bad-practice, design, convention