Clojure is not Software Conservative
…even if there is such a thing.
The post is meant as a very narrow response to a point Yegge made recently. I haven’t had time yet to sufficiently think through the premise that there is a single dimension on which developers worldviews can be plotted to usefully explain their opinions. Nor have I yet formed opinions on many of the other points he makes. I won’t make claims about whether software conservatism is better or worse than not-SC, or which direction I wish Clojure would move if there is such a spectrum. His post was entertaining and thought-provoking as is so often the case.
Instead I want to disagree just with Yegge’s argument that Clojure and its community align with his definition of SC.
He lists 17 items in his SC bucket. Of these, only 4 apply in any way to Clojure:
Nonpublic symbol visibility modifiers (private/protected/friend/etc.): Clojure does provide ^:private for vars, although it can be defeated by using the var explicitly with (deref (var foo)).
Build dependency restrictions: I’m not sure what this means, so I included it in case Clojure does it.
Software Transactional Memory: Clojure provides an STM system as one of several options for managing concurrency. Other options include atoms, agents (like local actors but less restrictive), vars (dynamically-scoped thread-local variables), locks, java concurrent queues and collections, volatile-mutable fields, and unsynchronized-mutable fields. The choice of which of these to use is left to the programmer.
Pure-functional data structures: Clojure provides a nice suite of persistent collection types, as well as convenient access to all of Java’s mutable collections, both the synchronized and unsynchronized varieties.
Matching 4 out of 17 isn’t very convincing.
Yegge also lists several items as the opposite of SC. Of those, here are the ones that I think nevertheless apply to Clojure: Eval. Metaprogramming. Dynamic scoping. Reflection and dynamic invocation. RTTI. Lisp macros. Domain-specific languages (for the most part). Optional parameters. Extensible syntax. Downcasting. Auto-casting. Debuggers. Whole-namespace imports. Thread-local variables. Value dispatch. Arity-based function overloading. Mixed-type collections.
That’s enough to suggest either that Clojure is not SC or that the very dichotomy is suspect.
Yegge raises two concrete points about Clojure in particular to define it as SC:
1. “Clojure's community came pre-populated with highly conservative programmers from the pure-functional world: basically Haskell/ML types”
I’m not sure what he means by “pre-populated”, but it in the recent survey, users of Haskell, ML, and “no answer” add up to a total of 7% of respondents.
2. “there was a key presenter doing a talk on how Macros were basically harmful and should be avoided”
I think this is a misunderstanding of Christophe Grand’s point. Here is the abstract: “Too often, one writes a DSL by starting with macros. However, this is often a case of premature optimization. An approach centered around "DSV" (domain specific values) and an interpreter leads to greater dynamicity. Macros can be added afterwards for optimization purposes or as syntactic sugar.” This is not about being scared of unusual syntax, but that functions and data are more flexible building blocks than macros and the best role for macros is on top of good building blocks.
If Yegge feels Clojure is a poor fit for him, it must be for reasons somewhat different from what his article claims.
I think it’s more interesting to look at how Clojure differentiates itself from other languages, not by claiming conservative features but by talking about simplicity, power, and focus. Clojure strives for these goals by providing a set of powerful language features that are not available in any other single language.
Thanks to Joel Martin, Jeff Dik, David Rupp, and Jim Duey for help with this article.