kotlinx.coroutines icon indicating copy to clipboard operation
kotlinx.coroutines copied to clipboard

start argument for produce.

Open jcornaz opened this issue 7 years ago • 3 comments
trafficstars

Since the onCompletion argument of produce is marked with InternalCoroutinesApi, the reason why it was introduced (#279) is back on the table.

In short: if a resource is open before produce, there is no (easy) way to make sure that the resource will always be closed.

The simplest solution, is probably to specify start = CoroutineStart.ATOMIC.

But for that we need a start argument to produce.

jcornaz avatar Nov 20 '18 16:11 jcornaz

Any update?

What should we do in the mean time? Is the best to use onCompletion despite the fact is it marked with InternalCoroutinesApi?

If yes could you mark it with ObsoleteCoroutinesApi instead?

jcornaz avatar Feb 24 '19 09:02 jcornaz

I'm working on a replacement DSL API for that. I have not yet created a separate issue for it (I'll have it soon). The approach I'm currently prototyping is this. You replace produce with produceBuilder (and it works for all other coroutine builders in the same way) and add catch/finally sections to it:

produceBuilder(...) { /* as before *}
    .finally { /* will be always invoked before completion */ }
    .build()

Here finally block is going to be executed before completion and in the same context as the coroutine (as opposed to the random thread that onCompletion used) and if this block fails, then the corresponding exception is going to become completion result of the job, similarly to how try { ... } finally { ... } works.

elizarov avatar Feb 25 '19 18:02 elizarov

I have a different use case for this. I have a coroutine that runs a loop to process a UI framework (calculate an initial state, wait for events, calculate new state, repeat). It starts this coroutine using the produce builder to publish updates on a channel. The coroutine is guaranteed to calculate its first state without suspending. In order to integrate with legacy, non-coroutine code, I need to get that first state from a non-suspend function.

As far as I know, there are two ways to do this:

  1. Call poll() on the channel. Assumes the initial value has already been sent.
  2. Call runBlocking { channel.receive() }.

I would prefer 1, because it doesn't actually block at all, and doesn't require the overhead of allocating a whole new dispatch queue and coroutine just to receive a value that should be immediately available anyway. However, the legacy code that needs to get this value is running on the same thread and hasn't given the produce coroutine a chance to execute its initial continuation yet.

I believe if I could start the produce coroutine with CoroutineStart.UNDISPATCHED, that initial value would get calculated and sent on the channel immediately, and I could use poll.

zach-klippenstein avatar Apr 25 '19 17:04 zach-klippenstein