Implementation patterns to support transactional functions

Let's go back now to why I had a hard time with using the STL std::map pattern.  It was because for the primary failure-prone access pattern (insert), there is an inverse operation which could not fail.

A common pattern in TxFn (sorry I can't keep writing the long name) is that you carefully do all your may-fail work and then you finish up with a series of statements which have no opportunity for failure.  The key is that all of the may-fail work has to either (a) not be an ESE or (b) be reversible.

To not be an ESE you can act in a "functional" manner - that is, rather than mutating some state, we can create a whole new copy of the state.  Then our caller would  wait until they're past the critical last point of failure and use a pattern like "nofail" swap() to then switch the new state into place.  This is just passing the buck, we may not be an ESE since we're functional but our parent still is an ESE and has to only use "functional" methods (which of course then means that even though this one function could be a TxFn, the caller would have to solve the probelm unless you're functional "all the way through").

This sounds good but when your state is a network of interrelated objects, it doesn't work.

Interestingly I just came across: https://www.paulgrenyer.dyndns.org/cppstyle/items.php#item12 whch basically opens a discussion of these same topics but unlike fun topics that everyone wants to debate like does snprintf() suck eggs, it delivers some guidance and then wanders away looking again for another pithy topic that might garner some talk show circuits or DDJ articles.  (This series would never get a DDJ article: "hey you jokers, fancy-pants new languages don't solve all your problems for you - you still have to write good code!  And the new languages aren't making it any easier!".)

Asides aside, this leaves us in the position of requiring that every (T)ESE which can be composed into a larger scoped operation be paired with a "nofail" partner.  There appears to be a fun exception to this which is that if you have one ESE operation which doesn't have a nofail inverse, you could do it as the last "mayfail" operation.  But then you're stuck unless the function that did this careful sequencing was main().

[mgrier: edited 5/10/05 to fix some wording around the functional pattern.  I accidently switched contexts between what the support code could do (act functional) and what the caller might do (build up state using functional metaphors and then use a nofail swap() type of thing).]