[Haskell-cafe] Re: Asynchronous exception wormholes kill modularity

Simon Marlow marlowsd at gmail.com
Wed Apr 7 11:49:44 EDT 2010

On 07/04/2010 16:20, Sittampalam, Ganesh wrote:
> Simon Marlow wrote:
>> I came to the conclusion that counting nesting layers doesn't solve
>> the problem: the wormhole still exists in the form of nested unmasks.
>> That is, a library function could always escape out of a masked
>> context by writing
>>     unmask $ unmask $ unmask $ ...
>> enough times.
> [...]
>> mask :: ((IO a ->  IO a) ->  IO b) ->  IO b
>> mask io = do
>>     b<- blocked
>>     if b
>>        then io id
>>        else block $ io unblock
>> to be used like this:
>> a `finally` b =
>>     mask $ \restore ->  do
>>       r<- restore a `onException` b
>>       b
>>       return r
>> So the property we want is that if I call a library function
>>     mask $ \_ ->  call_library_function
>> then there's no way that the library function can unmask exceptions.
>> If all they have access to is 'mask', then that's true.
> [...]
>> It's possible to mis-use the API, e.g.
>>     getUnmask = mask return
> Given that both the "simple" mask/unmask and your alternate proposal
> have backdoors, is the extra complexity really worth it?

The answer is yes, for a couple of reasons.

  1. this version really is safer than mask/unmask that count
     nesting levels.  If the caller is playing by the rules,
     then a library function can't unmask exceptions.  The
     responsibility not to screw up is in the hands of the
     caller, not the callee: that's an improvement.

  2. in this version more of the code is in Haskell, and
     the primitives and RTS implementation are simpler.  So
     actually I consider this less complex than counting
     nesting levels.

I did implement the nesting levels version first, and when adding 
non-interruptibility to the mix things got quite hairy.


More information about the Haskell-Cafe mailing list