Transactional Isolation may be a key component to combining Object and Functional technologies. In order to implement
CallByNeedSemantics the state that is relevant to the lazily evaluated expressions must be frozen until all such expression are no longer in use. That way all related expressions are calculated relevant to the same state regardless of when they are actually evaluated and will, therefore be correct with respect to each other.
Transactions provide a way to define and freeze relevant state and to clearly delineate the lifespan of
LazyObjects (objects that implement
CallByNeedSemantics).
TransactionSemantics can be implemented either optimistically (state is changed continually throughout the transaction and rollback means reversing the state changes) or conservatively (changes are accumulated off-line and only applied to the live state on a commit). If
TransactionSemantics are implemented conservatively then all objects that either implement or rely on
CallByNeedSemantics will be protected against unwanted state changes for the duration of the transaction. Once the transaction completes all objects that implement
CallByNeedSemantics can be discarded.
For example: in the game of life the data from all the cells must be read and processed before any of the cells is allowed to change. If we use a conservative implementation of
TransactionSemantics then we can use
CallByNeedSemantics to read the state of each cell
before it changes even though we use that data to cause changes to cells that haven't been read yet.
Years ago, in tackling just this simple example, curiously enough, I adopted an alternative strategy of doubling up the On and Off states into OnWasOn, OnWasOff, OffWasOn and OffWasOff. This allowed simultaneous access of current and former states, with the current state controlling the display and the former state being referenced, where appropriate, to determine the new state (I was actually referencing display pixels in a raster scan of the grid, so I needed to reference the current state of as yet unscanned pixels and former state of scanned and reset pixels). ThereIsNoStasis, after all.
(which is the same as storing two interleaved copies of the array, old and new, since an enum with 2 choices is 1 bit, while an enum with 4 choices is 2 bits)
The relationship between a conservative implementation of
TransactionSemantics and
LazyEvaluation is reciprocal. We've seen that
TransactionSemantics can be used to implement
LazyEvaluation as used by
CallByValueSemantics, but we can also use
LazyEvaluation to implement
TransactionSemantics in the conservative style that we require.
CallByValueSemantics focus on immutable state only. But
LazyEvaluation can also be used to control the timing of state changing operations. As the operations needed to effect the results of a transaction are discovered they can be encoded into
FunctorObjects with bound parameters and saved. Since the operations aren't actually executed the state won't change. Once it becomes time to commit the transaction the
LazyObjects can be destroyed and all of the stored
FunctorObjects can be executed thus moving the system to its new state.
CategoryObjectFunctionalPatterns CategoryLazyPattern