On 26/09/2025 14:04, Viktor Klang wrote:
:
>If the main scope body includes any blocking logic, it might end up
hanging indefinitely, while all the other forks have been cancelled.
That statement is true by definition—any code which is blocking
indefinitely and is not interrupted, is by definition blocking
indefinitely.
>The main scope’s body awaits for data from either of them (on a
queue), and when an element is produced, sends it downstream. Now, if
we’re not careful with error handling, an exception in one of the
substreams will cancel the scope, but the main scope will indefinitely
wait on data, not aware of the error.
This sounds, to me, like another issue with an absent
feature—Inter-task communication channels.
I agree, this example would be a good fit for channels.
On interrupting the main task ("Non-uniform cancellation" section in the
article), it's a good topic to discuss. When the scope is cancelled then
the outstanding subtasks are interrupted so that they finish up quickly
(their results aren't needed). It would mostly wrong to interrupt the
main task as you aren't looking for the main task to finish, instead you
want the main task to wakeup (from join) to process the outcome. It's
important to say that cancellation does not mean failure, it just means
there is an outcome, e.g. anyResultOrThrow cancels after any subtask
completes successfully. A lengthy/looping forking phase can use
isCancelled to avoid doing unnecessary work if needed. (Early prototypes
did interrupt the main task but this was problematic on many levels and
adds booking overhead to ensure that the processing of that interrupt is
restricted to code in the block.)
-Alan