STM needs a guarantee that all actions within are reversible. If you can launchTheMissiles in the STM transaction, then the STM cannot guarantee the desired properties.
One of the nice things in Haskell is that effects are typed. So STM can require its given actions to only have STM effects, and disallow full-fledged IO effects.
If you're willing to go by convention without compiler guarantees, then I'm not sure what advantage Clojure has over Java here, as an example?
- There is a IO macro that you can use to signal "Hey IO is going on you cant do this". I have jet to see this beeing used in production.
- Only Refs can change in Clojure (would be diffrent if you would have it in java)
- Refs are not really used that often. (in java everything changes all the time)
- Its easy to see/know if a function is dangerous because of naming conventions and other coding conventions
So why does "by convention" work out in Clojure and not in C#:
- Standard library is written with this in mind.
- Immutable Data structures are standard.
- The conventions where there since the language was created and get inforced both by the community and the language.
So you are right in terms of compiler guarantees you don't have much more in clojure then you have in Java but in the end it on the programmer that he writtes something that works. The stuff mention above seem to make it easy enought to work with them that people don't have a problem creating something that works with the STM.
One of the nice things in Haskell is that effects are typed. So STM can require its given actions to only have STM effects, and disallow full-fledged IO effects.
If you're willing to go by convention without compiler guarantees, then I'm not sure what advantage Clojure has over Java here, as an example?