https://kotlinlang.org logo
#coroutines
Title
# coroutines
r

rocketraman

04/01/2019, 9:17 PM
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

streetsofboston

04/01/2019, 9:18 PM
Copy code
suspend fun myFunction(...) = coroutineScope {
    ...
    async { ... }
}
r

rocketraman

04/01/2019, 9:19 PM
coroutineScope
automatically inherits the callers scope?
s

streetsofboston

04/01/2019, 9:19 PM
Yep, very handy 🙂
r

rocketraman

04/01/2019, 9:19 PM
I thought it started a new scope for some reason
Or I guess it does if there is no parent
s

streetsofboston

04/01/2019, 9:19 PM
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

rocketraman

04/01/2019, 9:21 PM
Good point
Thanks
s

streetsofboston

04/01/2019, 9:23 PM
You’re welcome 🙂
b

bdawg.io

04/01/2019, 11:12 PM
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

rocketraman

04/01/2019, 11:14 PM
@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

bdawg.io

04/01/2019, 11:16 PM
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

rocketraman

04/01/2019, 11:18 PM
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

bdawg.io

04/01/2019, 11:22 PM
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

rocketraman

04/01/2019, 11:23 PM
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

gildor

04/01/2019, 11:25 PM
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

rocketraman

04/01/2019, 11:29 PM
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

bdawg.io

04/01/2019, 11:33 PM
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

rocketraman

04/01/2019, 11:36 PM
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

bdawg.io

04/01/2019, 11:49 PM
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

rocketraman

04/01/2019, 11:51 PM
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

streetsofboston

04/02/2019, 12:04 AM
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

rocketraman

04/02/2019, 12:06 AM
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

bdawg.io

04/02/2019, 3:49 AM
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.
3 Views