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

Mark

09/16/2019, 8:33 AM
After updating coroutines (android) from 1.2.1 to 1.3.0 (same if 1.3.1) I’m getting this crash:
"kotlinx.coroutines.channels.ClosedSendChannelException: Channel was closed"
when calling
SendChannel.send
(note: I’m using
produce
to build the channel). I’ve isolated the cause to be this upgrade. I couldn’t find anything relevant in the release notes: https://github.com/Kotlin/kotlinx.coroutines/releases . Any tips on how to investigate what could be causing this, please?
o

octylFractal

09/16/2019, 8:35 AM
what does your
produce
look like?
l

louiscad

09/16/2019, 8:35 AM
Use
cancel()
instead of
close()
.
👍 1
m

Mark

09/16/2019, 8:42 AM
@louiscad I’m currently using
close()
because I have a reference to the channel (and I think there is no
cancel()
on
Channel
). Does this mean instead I need to hold onto a reference of the
Job
corresponding to the
Channel
instead (in order to cancel)?
o

octylFractal

09/16/2019, 8:43 AM
there is a
cancel
on Channel
specifically, it is inherited from
ReceiveChannel
m

Mark

09/16/2019, 8:48 AM
@octylFractal ah yes, sorry I was looking at
SendChannel
@louiscad thanks very much, using
cancel()
instead of
close()
fixed the problem. Is there a reference to this behavior change in the docs somewhere?
l

louiscad

09/16/2019, 8:54 AM
@Mark I think your best source is the documentation of both these functions. I learned about the difference between them the hard way after half an afternoon of debugging. You can submit an issue on GitHub to ask for it to be warned about in the guide/doc, and in the
close
function KDoc.
o

octylFractal

09/16/2019, 8:55 AM
yes, this is not really a behavior change --
close
is for the sending side, indicating it is done sending,
cancel
is for the receiving side.
essentially, a
close
should never be followed by a
send
, because the sender declared the channel to be closed (and similar for
cancel
& receiver)
👍 1
m

Mark

09/16/2019, 9:04 AM
Thanks @octylFractal that makes sense not to call
close()
from the receiver. I was actually calling it from a class managing the channels (when the channel becomes obsolete due to external conditions). So now I know
cancel()
is the correct way 🙏 But yes, a thorough reading of the docs is probably a wise investment of time!
d

Dico

09/16/2019, 9:12 AM
@Mark there's a major difference between cancel and close. Cancel causes elements not yet received to be dropped. Close doesn't.
The correct thing to do is to call close, not cancel. Moreover, produce will invoke close automatically when the coroutine completes for any reason.
m

Mark

09/16/2019, 9:18 AM
@Dico if I want to discard a channel (from the receiver side) surely I want the not-yet-received elements to be dropped?
v

Vsevolod Tolstopyatov [JB]

09/16/2019, 5:37 PM
The main motivation here is that attempt to send to a closed channel is either a close race (then channel should be cancelled, not closed) or a programmatic error. In the latter case, it should not be ignored, thus it became ISE instead of CE
👍 1