Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

One of the major advantages of software transactional memory that always gets mentioned is composability and modularity. Different fragments can be combined to produce larger components. In lock-based programs, this is often not the case.

I am looking for a simple example illustrating this with actual code. I'd prefer an example in Clojure, but Haskell is fine too. Bonus points if the example also exhibits some lock-based code which can't be composed easily.

share|improve this question
Interesting, but sounds more like a StackOverflow question to me. – Steve Haigh Apr 6 '11 at 20:50
This question has been asked there 4 minutes later.… Would someone migrate and merge this question (if possible)? – Job Apr 6 '11 at 20:54
Yeah after I posted it here, I realized it would probably be better on Stackoverflow. If someone can merge it, thats fine with me. – dbyrne Apr 6 '11 at 21:18
up vote 8 down vote accepted

Suppose you have some bank accounts:

(def accounts 
 [(ref 0) 
  (ref 10) 
  (ref 20) 
  (ref 30)])

And a atomic "transfer" function:

(defn transfer [src-account dest-account amount]
    (alter dest-account + amount)
    (alter src-account - amount)))

Which works as follows:

(transfer (accounts 1) (accounts 0) 5)

(map deref accounts)
=> (5 5 20 30)

You can then easily compose the transfer function to create a higher level transaction, for example transferring from multiple accounts:

(defn transfer-from-all [src-accounts dest-account amount]
    (doseq [src src-accounts] 
      (transfer src dest-account amount))))

  [(accounts 0) (accounts 1) (accounts 2)] 
  (accounts 3) 

(map deref accounts)
=> (0 0 15 45)

Note that all of the multiple transfers happened in a single, combined transaction, i.e. it was possible to "compose" the smaller transactions.

To do this with locks would get complicated very quickly: assuming the accounts needed to be individually locked then you'd need to do something like establishing a protocol on lock acquisition order in order to avoid deadlocks. It's very easy to make a hard-to-detect mistake. STM saves you from all this pain.

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.