Anyone know if there's a reason `forEach` wasn't a...
# coroutines
w
Anyone know if there's a reason
forEach
wasn't added to the coroutines library for channels? I'm considering putting up a PR to add
forEach
and
forEachIndexed
to complement
consumeEach
and
consumeEachIndexed
, so that people may avoid the same mistake I made with
consumeEach
v
could you elaborate on your use-case please? I’m interested in channel lifecycle: You create it, you publish to it, you start consumption via
forEach
,
forEach
terminates, what next?
w
Sure. My use case is I like the convenient styling of
forEach
, but I don't want to close the
ReceiveChannel
when I stop listening/cancel the coroutine job that is consuming the
ReceiveChannel
I can replace my current usages of
consumeEach
with just a for loop like
for (element in channel) {}
, but I think
forEach
would read a bit more cleanly.
In this case I have some channels that are more similar to an
RxJava
stream, where some events are being published, and I'm only consuming those events from particular points within my android application.
v
Thanks.
I’m only consuming those events from particular points within my android application.
Important note (to be sure you’re aware of this): if you have multiple concurrent
forEach
on the same channel, then it’s non-deterministic who will receive specific elements. E.g. if you have activity, which writes to channel
channel
and two launched jobs, which invoke
channel.forEach
, it’s possible situation when one job receives all the elements and other receives none.
BroadcastChannel
can be used to avoid such problem.
My activity pauses, so I want to shut down the associated coroutines
If the activity is paused, not destroyed, is it necessary to shut down coroutines and create them again on resume?
l
@withoutclass `BroadcastChannel`s seem to be what you're looking for. You can
consume
them without them being closed
w
@Vsevolod Tolstopyatov [JB] thanks for looking out 🙂. Yep, I’m aware of the issues surrounding multiple coroutines reading. Given my current architecture of my app, I want to be able to shut down all jobs when an activity pauses, given that my presenter recreates all channels the view listens to
onResume
. I just see no effective difference between having to write my own for loop or having a
forEach
defined for convenience sake. @louiscad I have flip-flopped back and forth over using
BroadcastChannel
at least for some of my channels, especially from my BT service, though I am a bit unenlightened around how the channel handles new events when the capacity is limited. Consider that I probably don’t want to allow an unlimited number of BT packets to be queued up on the channel, I want them to be pulled out as soon as they’re read by the appropriate party.
I appreciate all the responses btw 🙂
l
@withoutclass It is a Bluetooth Classic client Android app you're working on?
That's how I started using coroutines (but it's among some prototyping code I wrote back then, which I'm not too proud of)
w
More or less, I’m in a scenario where I only need to read bluetooth LE advertising packets, no GATT required after all so I haven’t gotten a chance to try out your library
l
@withoutclass I did a library for BLE scanning about 2 weeks ago, you can guess how it's named 😉
v
I am a bit unenlightened around how the channel handles new events when the capacity is limited.
As a regular channel: it suspends on
send
.
I just see no effective difference between having to write my own for loop or having a
forEach
defined for convenience sake.
Imagine we have both
forEach
and
consumeEach
in
kotlinx.coroutines
. They look alike, but have different semantics. Sadly, many users don’t read documentation/javadoc carefully, so when they try to consume all elements from the channel, they will pick basically any of these two methods. And it’s not clear, what method should be chosen by default, and it’s not clear (by the name) what is the difference between them. So we’ve decided to have
consumeEach
which satisfy 99% of the users and not to add
forEach
, which, even though it’s useful sometimes, adds additional API ambiguity and is not that useful
👍 1
w
Ok sounds good, that’s why I asked my question 🙂