> Transactions are not modular because every function needs to know whether it’s already in a transaction or not, to be conscious of what global entry point in a completely different module owns the transaction. I fail to understand the section about why transactions are unmodular. I've never encountered transaction code where the initiator of the transaction would affect the computation; could anyone elucidate this?
If you start a transaction when the calling code already started a transaction, then either you get an error because nested transactions are forbidden, or a reference counter is incremented for the transaction, so that when you close your inner transaction, no commit is done at that point, and instead the commit is only done when outermost transaction closes.
This latter case means that you don’t know when your inner transaction really commits, and also if you perform multiple inner transactions and the later one fails, the earlier one will implicitly also be rolled back, because they are all really just one shared outer transaction.
Of course, you could use separate database connections with independent transactions, but then you get into deadlocks or other problems when you really work on the same data.
So you can’t have modules that build on each other, while each being able to use transactions independently from each other. Transactions don’t compose in that way.
You would basically have to “color” every function based on wether it may perform a transaction or not, and within a transaction block you would only be allowed to call functions that don’t themselves perform a transaction. It becomes more complicated when you have transactions that are not lexically scoped, but for example live in an object.