@TomasStanek the current code is like this:
if (isActive.getAndSet(false)) {
// First interrupts the other task
try other.cancel() finally {
main.pop()
cb(Right(r))
}
What happens is that the loser gets cancelled before the winner's result is signaled. Now if that cancellation logic is synchronous, there shouln't be any issues. But if that cancellation logic happens asynchronously, then indeed you might have issues, however cancelling a timeout
shouldn't be async obviously.
In the new code in that PR, it is now changed to this:
if (isActive.getAndSet(false)) {
// First interrupts the other task
other.cancel.unsafeRunAsync { r2 =>
main.pop()
cb(Right(r))
maybeReport(r2)
}
So now the cancellation can happen asynchronously, although there are some caveats here as well, because due to multi-threading, there's always the possibility that the finalizer you want might not be registered yet, but that's another discussion.
Resource
and struggling to understand why it's there; it appears superfluous to Bracket
, as Resource.use
requires an implicit Bracket
. Is this just so that if your clean-up code is unwieldy, you can avoid writing F.bracket(<my huge initialization/finalization code>)
?
io.Socket
into a Resource
. I guess that' swhere this is going ... but go on.
pure
.
pure
)
readFromFile
fails
bracket
closes a resource as soon as the F finishes emitting elements
pure
, you emit, so you have finished emitting, so the resource gets closed
emit
on Stream, the stream has not finished emitting, because a Stream, unlike IO, can emit multiple elements, and therefore the thing is still fine
stream1 ++ stream2
stream1
sleep
(or delay or whatever) doesn't produce any values, it is only evaluated for effects.