I've been following the MVar debate with some interest.  As I've
mentioned in other mail, M structures were an Id thing, and so we here
at MIT are in some sense responsible for their peculiar
non-uniformity.

It should be noted that M-structures were defined by analogy to
I-structures---which are write-once, read-many.  Thus, putMVar signals
an error on a full location primarily because the I-structure write
did as well.  This non-uniformity stems from the fact that we can
easily cook up an MVar implementation which stores queued reads in the
same storage which it uses for the data (which is what I-structures
do).  It's an implementation hack.  I have no idea whether this is
true in GHC (I don't have the source handy right now), but I suspect
it isn't quite.

Really, it does seem to me that MVar behavior _ought_ to be
symmetric.  In this case, there are two options:
 * M-structure operations block.  This shouldn't be a problem in 
   practice, as M-structures mostly get used in a producer-consumer
   fashion, where this is what we want, or they get incrementally
   updated, in which case we should be able to prove that suspension
   on write is impossible (though the necessary compiler logic may
   not be worth the bother).

 * M-structure operations don't block.  This breaks one of the
   important early M-structure ideas: That the presence state of the
   M-structure was invisible and enforced by the underlying
   synchronization.  On the other hand, when we're using M-structures
   for e.g. caching we end up wasting a lot of effort coding up
   presence state explicitly in another MVar.

Alas, my instinct is that Claus Reinke's "tryButDoNotSuspend" probably
isn't the right way to go here.  Effectively what it does is "change
the mode" of the IO monad, altering the behavior of M-structures.  It
seems to me that blocking and non-blocking operations really are
fundamentally different and have fundamentally different underlying
implementations, and there should simply be a separate set of
operations for each.  I don't see an obvious way to code up the
suspensive operations using the non-suspensive ones, since you want to
associate the suspension state with the MVar (and do so atomically, in
case someone else is trying to change the state).  

My conclusions:
   The suspensive behaviors are necessary.  At least one, and
   preferably both of takeMVar/putMVar must be suspensive.

   The non-suspensive behaviors are nice, but should be captured using
   separate operations.  Cooking them up using multiple MVars will
   work, but is arguably only necessary because the implementation
   isn't flexible enough.

-Jan-Willem Maessen

Reply via email to