On Aug 23, 7:28 pm, Tom Davies <[EMAIL PROTECTED]> wrote:
> I know this is a very old thread, but I think the composition question
> deserves a better answer.
>
> cliffc wrote:
>
> [snip]
>
>
>
> > Ok, the long sought after counter example.: STM's do not compose w/
> > correctness.
> > Bad Java syntax follows, because I don't 'speak' Clojure.  I'm using
> > the classic example.
>
> > class Account {
> >   long _money;
> >   add( long m ) { atomic { _money = _money + m; } }
> > }
>
> > transfer( Account a1, Account a2, long m ) {
> >   a1.add( m);
> >   a2.add(-m);
> > }
>
> > While 'add' alone is STM'd & safe, the two calls to 'add' that need to
> > be wrapped in an 'atomic' are not - so there is a race where the
> > accounts do not balance.  Deciding at what level to add the next
> > 'atomic' (should it be around 'transfer' or at a higher level or not
> > at all?) demands the programmer have domain knowledge not already
> > encapsulated in the Account class.  THIS is the source of vast numbers
> > of bugs.
>
> Of course the programmer needs to know what the scope of a transaction
> should be, i.e. what set of mutations of global state need to be
> atomic. That's true of any scheme for using transactions.
>
> I agree that the code above makes it hard to compose functions,
> because you can't see where transactional variables are modified.
>
> Haskell solves this nicely by statically typing STM operations, so
> that you know when a function is an operation which modifies
> transactional state. See this 
> paperhttp://research.microsoft.com/~simonpj/papers/stm/beautiful.pdf
>

Haskell does _not_ solve the transaction composition problem, it
simply prevents composing transactions.

Composing transactional activity is not the same as composing
transactions. Clojure supports both - you can write functions that
modify refs and have no dosyncs of their own, and thus must be placed
inside a transaction at a higher level (or else will generate a
runtime exception), or, write independently-transactional functions
that can be run successfully on their own _and_ be composed into a
single transaction by higher-level code.

> In Haskell the types of example above would look like:
>
> add :: Account -> Money -> STM ();
>
> addInTransaction :: Account -> Money -> IO ();
>
> where addInTransaction matches your add() method, by applying
> 'atomically' to the result of add.
>
> so if you write transfer as:
>
> do
>   addInTransaction a1 m
>   addInTransaction a2 -m
>
> it is very clear that you are doing two IO operations, each with its
> own side effects, in sequence, and the type system won't allow you to
> wrap the two addInTransaction calls in an atomically, because the type
> of atomically is:
>
> atomically :: STM a -> IO a
>

All that means is that you can't do in Haskell what Cliff and everyone
else used to using transactions wants to do - take existing functions
that, when run independently, execute transactions (fully!), and
compose them into a single transaction.

I don't think the foo/fooInTransaction system is workable. Functions
that call STM() functions are going to have to choose between calling
atomically or being STM() themselves, leading to larger-than-desired
transactions and a lack of modularity.

Rich


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to