We’ve all heard Greenspun’s Tenth and only rule. It’s often applied to non-Lisp programming languages as well as to larger applications. It prognosticates that, eventually, all languages will become Lisp. One assertion that follows from Greenspun’s rule is that if all languages are going to turn into Lisp anyway, why not just start with Lisp? But judging from the available features in languages today, perhaps it is too late to “just start with Lisp”. Inspired by a post that found its way to my trusty feed reader, I think it may already be too late.
Greenspun’s Tenth rule, from the Wikipedia entry, reads as follows:
The basic idea is simple: as a program grows in complexity, the developers need to start reigning in the resulting chaos. Automatic memory management is added. Functional utilities start to pile up. Pretty soon, they fire up a parser generator and add some DSL’s and a prompt. Eventually, it’s just a hacked together version of Lisp without the parentheses.
The same, it can be argued, happens with programming languages. At first, they can only do basic scripting language stuff. Then the intrepid programmers discover the utility of a map operation. Maybe they implement a debugger. Or they really need anonymous functions. And, like before, it’s not-quite-Lisp.
When faced with the prospect of having to manage a buggy, home-built codebase when all of the features you will have to develop anyway are already well implemented in Lisp, it seems like a no-brainer what you’d choose.
And I think that for a long time, this was true. But is it still true? What do we have now? The big players in the field are Java, C#, and Python. You might add Javascript to that list, too, depending on how you count it.
All of those languages have managed memory. Most have a decent debugger and feature-laden development environments. They run on different platforms. Python has decent functional-style programming. C# has some cool language development tools. They’ve got all these features that Lisp had long ago. But three things have changed—they’re not ad hoc. They’re not informally specified. And they’re not buggy. The only thing that’s still true is the slow thing for some of them and they’re still half.
So, really, I think that Lisp, or its brainchildren, are yes, mainstream. So long did I think that my obsessive desires would lead me away from the mainstream. No, they only bring me closer to Java. Or, put another way:
That quote is from Guy Steele. Halfway to Common Lisp? That seems awfully close to voluntarily following Greenspun’s Tenth Rule. James Hague over at Programming in the 21st Century has a similar view on the matter. He says Functional Programming is Mainstream—and has been for a while. Other programming languages have half of Lisp—and more that Lisp doesn’t have. Lisp, or its essence, is mainstream. And after bringing the fire of Lispy programming to the world of languages, it is forced to face the onslaughts of a growing amount of weenie-bashing for all of eternity.
Ok. Maybe that was melodramatic. My point is that it may be too late to start with Lisp so you don’t have to reimplement all of its features. Because all of those new languages have already implemented them. At least what most people consider the important ones.
I imagine people will disagree with this view. People might say that although Java and C# have many of the features that made Lisp great, it doesn’t have the essence that makes Lisp still the best choice for discriminating programmers. That essence might include meta-programming facilities, or first-class closures, or macros.
Macros let you subsume more code into less code. Macros let you write more functionality with fewer lines. Macros let you abstract away boilerplate into new syntax.
But the corporate manager will say: if everyone writes their own syntax, my programmers can’t read each other’s code. So instead of having to learn a language once, they will have to learn a new language each time they approach a program for the first time. And the value of macros is lessened.
Code as data lets you manipulate code at runtime. It means you can optimize it, count it, store it, send it somewhere, and more importantly, write it in itself. The possibilities are endless.
But the corporate manager again has an answer: Java is already written. Why would I want to rewrite it? I have a program to develop—and you’re worried about optimization? Let the folks at Sun worry about that. We’re not language developers!
And so do each of the features fall like dominoes. Either they hinder some unforeseen corporate best-practice, or they just aren’t really as powerful in that environment as one would really hope their expressive purity would like.
Python really seemed to be playing out Greenspun’s Tenth for a while. I mean, really. Cool functional programming features. Strong support for a list-like basic type. Functions as the primary means of abstraction. And people were talking about it. They still do. And there was a sparkle of hope that one day, all of the features of Lisp would make it into Python. And that day would come when people realized that those other features were great. The Pythonists just didn’t know how useful those features were. They just never used them before.
Check out this story as witnessed by Kenny Tilton.
I quote this somewhat long story here because it really shows the dynamic. One person claims that they’re close enough to be called a Lisp. Another guy pointing out “but you don’t have this feature”. It’s just perfect. Python seems to be following that solitary Tenth Rule.
But the bomb was dropped, folks! Python, in its newest incarnation, is breaking the Rule. After absorbing all sorts of functional goodness from the Lispy womb, Python is rejecting its uterine confines! The news that Python 3000 (its projected release date) will reject lambda (!), map, filter, and reduce shocked the Functional Programming World. They later recanted some of it. But it is a bold statement against the tyrannical rule of Greenspun.
And Peter Norvig? The author of Paradigms of Artificial Intelligence? He knows about those other features of Lisp. Trust me. He knows what he’s missing. And he chose Python.
I guess my point, through all this meandering, is that other languages did borrow a lot from Lisp. About half of it. And now those features are out there, in the world. And in the meantime, while they were borrowing, they got some new features of their own. Features like giant user bases, gazilions of libraries, corporate support, standards bodies. So Lisp has half of the features of Python. Java and Python are far from my ideal language—but so is Common Lisp. The idea that I would have to implement so much of Lisp on my own is a little overblown these days. And speaking of reimplementation: How much of Python’s standard library does a complex Lisp program reimplement? How much of Python would you have to reimplement before you regret choosing Common Lisp?
