Hi Guido, On 14-05-27 11:03 AM, Guido van Rossum wrote: > A cancellation, however, is different. It is initiated by the > *consumer* to indicate that it is no longer interested in the result.
I think out of everything you said (and thanks for the nuanced explanation), this could be the crux of the disagreement Your scenario describes a producer and a consumer, but the cancellation isn't /necessarily/ initiated by the consumer. It could be, as in my case, initiated by an outside agent. For example, imagine a download manager coroutine that starts a number of download coroutines. An outside supervisor may cancel one of the download tasks (say by user request). The download manager is the consumer of the download coroutine, but it's not the one that cancelled the task, so I argue it's a surprising side effect that the download manager is also terminated silently (even while the other download coroutines live on, if they were gather()ed). By requiring CancelledError to be explicitly caught to suppress noisiness, it's at least spelled out in the code what the effects of cancellation are. Maybe a given yielded coroutine can be cancelled without consequence, or maybe not. When cancellation is noisy, it forces the programmer to specifically think about happens when yielded Future is cancelled. One ugly case with the current behaviour is to debug why some coroutine 5 levels up just stops for no reason, where it might be sufficiently far enough removed from the sub-task that got cancelled that the programmer might not even connect the dots. > As an experiment, I added "self._log_traceback = True" to > Future.cancel() and ran the unittests. There were 81 log messages > about cancelled Futures. I think this speaks for itself; I wouldn't > want to add extra code just to suppress that exception to all those > perfectly fine tests. Isn't this the tail wagging the dog? You've developed unit tests for a particular behaviour. Here the discussion is about changing the behaviour, and the argument against changing that behaviour is that the test cases would need to change too. It seems like an argument from inertia, or maybe argument by popularity, rather than addressing the the idea on its own merits (like you did in your earlier explanation). Also by calling the tests "perfectly fine" you're begging the question. :) > I've seen your patch now, but I really would like to find a way to > convince you do come up with a different way to achieve what you're > trying to do. Your change would suddenly add a communication channel > back from the consumer to the producer that can transmit any amount of > data (through exception attributes), compared to the single > "cancelled" bit that we currently have. True, and this could be abused. But aren't we all consenting adults here? :) > Can't you create an object that is shared between consumer and > producer where the consumer can indicate the difference between soft > and hard aborts? I could, but it's inelegant, and would violate the boundaries of cleanly separated layers of the application. Specifically, if I have coroutines A -> B -> C, if C is "soft cancelled" by some outside supervisory task S, then B handles this case and continues on working. If C is "hard cancelled" then B should stop and A needs to be aware of this and handle it appropriately. The way this works with custom cancellation exceptions is S would do C.cancel(SoftCancelledError) or C.cancel(HardCancelledError) depending on the case. When B yields C, it catches SoftCancelledError and can clean up and continue on. HardCancelledError isn't caught in B, so it bubbles up to A which catches it and takes some higher level action. With what you proposed, S would need to know how to pass a message to /B/ (and B could be multiple possible objects depending on the case) to indicate the task that just got cancelled was a /soft/ cancel. And it'd similarly need to know how to pass a message to /A/ (which could again be multiple possible objects) to indicate the task that got cancelled was a /hard/ cancel. So the fact of the cancellation is in band, but the /type/ of cancellation is out of band. Doesn't that seem kludgy? If I had to pick one battle to fight between the two issues, it'd be this one. I can live with silent cancellations as it just requires me to pay attention, whereas the inability to cancel with custom exceptions requires inelegant workarounds. Thanks for the insight so far, Jason.
