I have a question about Coroutine Scopes and the `...
# coroutines
j
I have a question about Coroutine Scopes and the
coroutineScope
function… I have a class such as this, which is inherently a scope…
Copy code
class MyClass(...): CoroutineScope by CoroutineScope(Dispatchers.Main) {
  suspend fun doThing(): String = coroutineScope {
    return "Foo"
  }
}
Is the code that runs in the coroutine defined by the call to
coroutineScope
guaranteed to be run in the context of the
MyClass
scope? Even if
doThing
is called from a different scope? If so, how does that actually work? Another way to state the question is, is the scope that is inherited defined at compile time or at runtime?
k
Nope. The
CoroutineContext
of a coroutine can be changed by the function
withContext
. If any of the coroutines run within
doThing
call
withContext
this can happen. Also, you’re not launching a coroutine within the scope
MyClass
has. You’re defining a suspending function which can be run from anywhere. To define parent-child relationships you use any of the coroutine builders or manually create the relationship when constructing a CoroutineScope. Eg.
Copy code
suspend fun main() = coroutineScope { // scope 1
  launch { // this: CoroutineScope, aka scope 2 child of scope 1
    first()
  }

  launch { // this: CoroutineScope, aka scope 3, child of scope 1
    second()
  }
}

suspend fun first() { 
  delay(1000000000))
}

suspend fun second() = coroutineScope { // scope 4, child of scope 3
  launch { // scope 5, child of scope 4
    delay(1000)
  }

  launch { // scope 6, child of scope 4
    delay(1000)
  }
}
j
Ah okay, that makes sense. I had found this SO answer that indicated that
coroutineScope
and
withContext(this.coroutineContext)
were equivalent. But, that didn’t make a whole lot of sense based on the implementation of
coroutineScope
. (Although I was kind of hoping that it would work that way.) https://stackoverflow.com/a/56866621
k
Functionally, they are equivalent. They both create a new coroutine scope as a child of the parent scope and run some work. They’re implemented differently and you shouldn’t really ever be doing
withContext(currentCoroutineContext())
s
There is a small mistake in the linked StackOverflow thread which is probably contributing to the confusion. It says that
coroutineScope { }
is like
withContext(this.coroutineContext)
, but actually it’s like
withContext(coroutineContext)
. The top-level coroutineContext property, which gets the current coroutine context of a suspend function invocation, is a completely different property from the coroutineContext property of a coroutine scope. Since your example contains both a suspend function and a coroutine scope, both are present and one will hide the other.
The
currentCoroutineContext()
function exists as an alternative to the top level
coroutineContext
property for the purpose of resolving that ambiguity when necessary