
On 12:31, Thu, Nov 13, 2014 Yuras Shumovich
hClose is a good example because it's pervasive and currently incorrect. But it's not the only one, and furthermore a lot of broken code is likely in libraries.
hClose is pervasive, but it doesn't mean the bug in it affects a lot of code. Probably 99.(9)% hClose uses are correct. (it may affect more code then I think, but nobody even created a ticket yet!) Do you really think it is common to close handle while using it from other thread? No, but that's not a general requirement for this problem to manifest. Besides, why shouldn't one be able to safely close a handle while another thread may be using it, without using arcane functions? But yes, there is a lot of broken code in libraries. But we should fix bugs instead if hiding them. This isn't about hiding bugs. It's about changing the semantics of exception handlers so that they are more likely to match what's desired in the general case.
For the most part, Haskellers don't need to worry about async exceptions. using them properly is a rather rare skill currently, and I suspect people are basically happy with that. But it's dangerous because people actually do need to write async-safe code in cleanup handlers to get the behavior that usually mean. One reason I think changing bracket etc is a better solution is that it helps minimize the average programmer's exposure to async exceptions. It becomes easier to write correct cleanup handlers,
for
everyone. And if someone really needs an interruptible handler that can be available by a specialized function. But bracket and catches aren't the place for that.
Haskellers don't *want* to worry about async exception, but then should. Otherwise let remove exception from language (yes, including synchronous -- average Haskeller doesn't worry about them too.) Why should Haskellers worry about async exceptions? The vast majority will never use them. They are difficult to reason about and difficult to use properly, and it's only because certain aspects of the RTS (and killThread) are implemented with them that most people ever encounter them. The proposal makes it easer to continue ignoring async exceptions. That is why I'm arguing here against it. (Possible breakage if existing code worries me too, but much less) I think it's a good thing to make it easier to ignore async exceptions. It is common myth that bracket saves you from async exceptions, but that is simply not true. And the proposal will not make it true. So newcomers learn to ignore async exceptions and continue doing that forever. Even worse, when newcomer finally find out (most likely itself!!!), that the myth is wrong, he doesn't get help from the community -- no docs, no tutorials, no blogs. Everything he can find is a set of myths. Or we could make the implementation match the common knowledge. Then it wouldn't be a myth, it would be true. I started learning haskell 8 years ago, and I'm paid for haskell code 3 years already. When do you think I discovered that bracket is not enough to handle async exceptions? Half a year ago(!) I'll post the link again: http://haskell.1045720.n5.nabble.com/Control-Exception-bracket-is-broken-td5... Note that nobody answered the question about hClose. Nobody explained how to use interruptible exceptions in cleanup. Very few people actually even care to replay. Because everybody learned to ignore async exceptions. Did you read this: http://www.well-typed.com/blog/97/ ? I hope you did. Because it is probably the *only* deep discussion of *some* of the related issues. Unfortunately it appears after too late for me, so I spent a lot of days discovering everything myself. Wouldn't it be better if stuff like that just worked out of the box? People could still spend days learning it, but they wouldn't be bitten by these hard-to-identify, poorly-understood bugs. I even wrote my own library for exception handling: https://github.com/Yuras/io-region/ I'm still not sure it is good. It even can be buggy. But I considered a lot of design decisions, including unintrruptibleMask, and found then unsatisfactory . I personally find it easer to write exception safe code with io-region, but you should understand async exceptions anyway. There is no easy way unfortunately. That doesn't mean we should make it harder to do the right thing. John
So sync exceptions in hClose mean the program is incorrect, and the only recourse is to prevent the sync exceptions in the first place. Fortunately, these FDs are likely guaranteed to be valid so sync exceptions are virtually ruled out.
This is a general pattern with cleanups: a cleanup already has the allocated resource at hand, which almost always rules out sync exceptions. Also, exceptions during an error-induced cleanup cause dangerous error-silencing anyway since we cannot handle an exception within an exception.
So you have to inspect all the code, directly or indirectly used by cleanup action, to ensure it doesn't throw sync exception (just to
find
that it is not the case -- a lot of cleanup actions can throw sync exceptions in some, probably rare, cases.) Someone argued, that was exactly the issue the proposal was trying to solve.
Sync exceptions have nothing to do with the proposal. The proposal itself certainly doesn't argue this.
Sorry, I was not clear enough. I'm referring to the next:
On Tue, 2014-11-11 at 12:17 -0800, Merijn Verstraaten wrote:
Both Eyal and me have had trouble with this where we had to entire half of base and part of the runtime, to figure out whether our code was async exception safe. Auditing half the ecosystem to be able to write a safe cleanup handler is *NOT* a viable option.
By banning sync exceptions in cleanup action you require Merijn to audit half the ecosystem to figure out whether his code is *sync* exception safe. Which probably requires the same amount of work as inspecting code for *async* exception safety.
What? Nobody wants to ban sync exceptions in cleanups. They should continue to work the way they do now. Why do you bring this up?
So sync exceptions in hClose mean the program is incorrect, and
I'm referring to this: the
only
recourse is to prevent the sync exceptions in the first place.
What can it means except banning sync exceptions? Actually I seriously considered baning exceptions in cleanup action, but found it unsatisfactory Sorry for long email. Thanks, Yuras