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

Zach Klippenstein (he/him) [MOD]

09/21/2018, 1:06 PM
Might be jumping the gun here because the
api-review
branch hasn't been merged yet, but i noticed this commit deprecates the
onCompletion
parameters to launch, async, etc. What's the best way to wire up channels to cancel on coroutine completion after this change? Explicit try/catch in the coroutine? (Is there a discussion about this change anywhere I could read up on?) https://github.com/Kotlin/kotlinx.coroutines/commit/3049652ff5e3a23e35bcc82e28fb87936ed836ec
Also, seems like
Channel.consumes()
should also be deprecated.
v

Vsevolod Tolstopyatov [JB]

09/21/2018, 2:09 PM
What’s the best way to wire up channels to cancel on coroutine completion after this change?
using
invokeOnCompletion
🙂 It’s deprecated only as launching argument. You still can write
Copy code
val job = launch {}
job.invokeOnCompletion
What about channel closing — I’d glad to see your use-cases. Closing channel from the
async.onCompletion
is rather a smell that
produce
or
actor
should be used
z

Zach Klippenstein (he/him) [MOD]

09/21/2018, 3:22 PM
I’m writing a coroutine builder that is basically
async
,
produce
, and
actor
all in one. Internally the coroutine can send on one channel, receive on another (of a different type), and return a value. Externally the builder returns an object that has a
SendChannel<O>
, a
ReceiveChannel<I>
, and a
Deferred<R>
. The implementation looks something like:
Copy code
fun <I, O, R> CoroutineScope.foo(block: suspend FooScope<I, O>.() -> R): Foo<I,O,R> {
  val inputs = Channel<I>()
  val outputs = Channel<O>()
  val result = async {
    val scope = object : FooScope<I, O>,
      ReceiveChannel<I> by inputs,
      SendChannel<O> by outputs {}
    return@async scope.block()
  }
  result.invokeOnCompletion { cause -> inputs.cancel(cause) }
  result.invokeOnCompletion { cause -> outputs.cancel(cause) }
  inputs.invokeOnClose { cause -> result.cancel(cause) }
  outputs.invokeOnClose { cause -> result.cancel(cause) }
  return object : Foo<I, O, R> {
    override val inputs get() = inputs
    override val outputs get() = outputs
    override val result() = result
  }
}
This definitely isn’t ideal – everything has to be manually wired up to cancel everything else, so I would love to find a simpler way to write it.
I could write this with triple-nested
async
,
actor
, and
produce
builders I guess, but then I’m starting three coroutines when I only need one, which seems wasteful.
v

Vsevolod Tolstopyatov [JB]

09/21/2018, 4:54 PM
Thank you for a use-case. It’s definitely hard to cover with one builder 🙂 We are not going to remove
invokeOnCompletion
, so everything should work for you as before
👍 1
6 Views