I have a suspend function, in which I want to star...
# coroutines
r
I have a suspend function, in which I want to start an
async
block. I'm assuming this is the right way?
Copy code
CoroutineScope(coroutineContext).async { ... }
đźš« 1
s
Copy code
suspend fun myFunction(...) = coroutineScope {
    ...
    async { ... }
}
r
coroutineScope
automatically inherits the callers scope?
s
Yep, very handy 🙂
r
I thought it started a new scope for some reason
Or I guess it does if there is no parent
s
It’s a new CoroutineScope instance, but it inherits the context of the outer-one
There always is a parent/outer-scope
Only other suspend funs or coroutines can call suspend funs. And coroutines can only be built by
launch
or
async
which need a CoroutineScope
✔️ 1
r
Good point
Thanks
s
You’re welcome 🙂
b
One thing to note is that the following function will not return until all the work in the
async
coroutine is completed
Copy code
suspend fun myFunction() = coroutineScope {
    async { doSomethingSlow() }
}
r
@bdawg.io Why would that be surprising? It should suspend on the async work as usual... if one wanted to return immediately that would need to be
launch
.
b
It doesn’t matter,
launch
does the same thing. Any coroutines started inside of a
coroutineScope { ... }
will prevent the
coroutineScope
function from returning until all children coroutines have completed
I didn’t give an alternative because
coroutineScope
is better if it works for what you’re doing 🙂
r
Ah right. In my current case it doesn't matter because I need to use the value returned from the
async
anyway. But theoretically speaking, what's the alternative if one did want the fire-and-forget behavior, but still run it within the parent scope?
b
The convention is to accept the
CoroutineScope
as a parameter (usually as an extension, see the `launch`/`async` implementations).
Copy code
fun CoroutineScope.myFunction() = async { doSomethingSlow() }
r
Yeah, that's what this code looked like originally but recent versions of IJ/Kotlin plugin raise a warning when its used as a receiver of a suspend function: "Ambiguous coroutine scope calling async".
I actually don't see how it really is ambiguous, because removing the CoroutineScope receiver results in a compile error. It may just be a bug in the plugin.
g
Right, and this valid warning, but not for Bradyn's sample Could you show your code that cause this warning? Probably you have unnecessary
suspend
r
Copy code
private suspend fun CoroutineScope.foo(): String {
    val b1 = async {
      bar()
    }
    val b2 = async {
      bar()
    }
    return b1.await() + b2.await()
  }

  private suspend fun bar(): String {
    TODO()
  }
message has been deleted
b
yeah, it’s because of
suspend
being used in conjunction of a
CoroutineScope
receiver. All suspend functions have a
coroutineContext
property that can be read, so it’s warning about the shadowing that occurs with that afaik.
In that given sample, you should use
coroutineScope { ... }
instead (which is the point of the OP) 🙂
r
Yes, exactly, which was why I posted in the first place. Note it's not shadowing though. It doesn't compile if you remove the scope receiver, which a shadowed function would do.
b
The
coroutineContext
is what’s shadowed, not the
CoroutineScope
that
async
needs, which doesn’t exist without a) it being passed or b) using the
coroutineScope
method
r
I get that, but
coroutineContext
isn't directly usable by
async
, so why the warning on
async
? The separate warning on
CoroutineScope
makes sense.
I guess we're splitting hairs here now though.
s
It's also a convention. Either use
suspend fun xxxx(...)
that suspends or do
fun CoroutineScope.xxxx(...)
that must return immediately. Don't mix them. If your
suspend fun
needs to do something parallel, using launch or async, use
= coroutineScope { ... }
r
I knew about the first part, but got the second wrong... ^- if this text was in the warning given by IJ, a lot of effort could have been saved! 🙂
đź’Ż 1
b
It’s not because of
async
. The warning is “Ambiguous coroutineContext due to CoroutineScope receiver of suspend function” and it’s ambiguous because suspending functions have a
coroutineContext
and having a receiver of
CoroutineScope
shadows that with the scope’s
coroutineContext
. It’s just manifesting that with
async
as well because it utilizes the context, but structured concurrency requires that to go through a scope.