
On Wed, Sep 10, 2008 at 2:55 AM, Maarten Hazewinkel
And a further note on sharing memory via a transactional resource (be it STM, a database or a single controlling thread). This situation always introduces the possibility that your update fails, and a lot of client code is not designed to deal with that. The most common pattern I see in database access code is to log the exception and continue as if nothing happened. The proper error handling only gets added in after a major screwup in production happens, and the usually only the the particular part of the code where it went wrong this time.
This seems to be a bit too much F.U.D. for STM. As long as you avoid unsafeIOToSTM (which you really should; that function is far more evil than unsafePerformIO), the only failure case for current Haskell STM is starvation; some thread will always be making progress and you do not have to explicitly handle failure. This is absolutely guaranteed by the semantics of STM: no effects are visible from a retrying transaction--it just runs again from the start. You don't have to write "proper error handling" code for transactional updates failing. The only reason why this isn't possible in most database code is that access to the database is happening concurrently with side effects to the local program state based on what is read from the database. Removing the ability to have side effects at that point is what makes STM great. It's easy to make side effects happen on commit, though, just return an IO action that you execute after the atomically block:
atomicallyWithCommitAction :: STM (IO a) -> IO a atomicallyWithCommitAction stm = join (atomically stm)
-- ryan