This may be more suited for some #designpatterns room, but I've been knocking around this idea that Clojure is a "Causal Manifold Oriented Programming" language. The idea is that the concurrency metaphor used in Clojure, where everything fits into the four quadrants of concurrency, creates a "hygienic transformation" model in the mind of the programmer, which she can discuss with others in a common way. The consistency of operations across time creates this causal manifold model.
Here's the quadrants:
Coordinated Uncoordinated
Synchronous Refs Atoms
Asynchronous — Agents
Coordinated
An operation that depends on cooperation from other operations (possibly, other operations at least do not interfere with it) in order to produce correct results. For example, a banking operation that involves more than one account.
Uncoordinated
An operation that does not affect other operations in any way. For example, when downloading 100 Web pages concurrently, each operation does not affect the others.
Synchronous
When the caller's thread waits, blocks, or sleeps until it has access to a given resource or context.
Asynchronous
Operations that can be started or scheduled without blocking the caller's thread.
(from <http://clojure-doc.org/articles/language/concurrency_and_parallelism.html>)
A causal manifold is actually pretty simple
At least, for my purposes, it's where state is thought of as a 2D surface, where temporal/causal relations into the future are projected onto a 3D tube-like thing
pictures of the evolution of the universe come to mind:
going from big bang to present
or, looking more like the tube: https://img.purch.com/w/660/aHR0cDovL3d3dy5saXZlc2NpZW5jZS5jb20vaW1hZ2VzL2kvMDAwLzA0OC81NDYvb3JpZ2luYWwvYmlnLWJhbmctaW5mbGF0aW9uLTAyLmpwZw==
Some more specifics on causal manifolds: https://en.wikipedia.org/wiki/Globally_hyperbolic_manifold and https://en.wikipedia.org/wiki/Causal_structure
So, the idea is that, whereas with object oriented programming, we think about objects and their relations, where interactions between the objects through time aren't clearly defined, with "causal manifold" oriented programming, we're leaning on a language that gives us a consistent model of those relations through time, such that we can talk together about that causal manifold in a consistent way.
Or maybe causal manifold isn't the right word...
But the basic idea seems to make sense
And even though we don't usually use STM/refs these days, it really does "complete" the causal manifold model, allowing for a consistent model across all Clojure programmer's minds
In a way, you could say that functional programming is "causal manifold" oriented. But then one might say that rather "causal manifold" oriented programming is where a language provides more and more tools to reason about that manifold/pipeline. Where even the datastructures, like in Clojure, efficiently participate in that manifold model.
And as another point of evidence, when I was at the last Conj, Guy Steele told me that his favorite aspect of Clojure was its 4 quadrant concurrency model, because Rich "got it right." So there's that too.
the quadrants are neat, but how often do you ever use a ref type besides an atom? I can think of one place at my last job where we used refs and agents, just for the agent post commit hook that refs have, not for the concurrency model, and I have one place at my current job where I recently thought "oh, this could be an agent" but haven't actually changed anything
agreed
I think they contribute more to our mental model, than our actual code though (refs and agents)
turns out, most problems are tractable with just atoms
@hiredman Zach Tillmen made that argument as well. If you have to ask, you should use a atom.