13

Greenspun's tenth rule (actually the only rule) states that:

Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.

My memory is that there are some papers on the topic, perhaps for Borland's Quattro (spreadsheet) project and possibly others. Google is unhelpful, maybe the right search terms are not coming to mind. I am looking for papers or articles supporting this claim, if any.

6

9 Answers 9

16

The statement is hyperbole. But there are obvious signs of Lisp envy in other languages. Look at C# and how it is becoming more functional in nature. Look at the various Business Process Management, workflow, and EAI frameworks that go out of their way to make it possible to program the system without changing the program.

There's a book on Domain Specific Languages by Martin Fowler that talks about how to do meta-programming in Object-Oriented languages. So there is some truth to the hyperbole.

Paul Graham called Lisp the most powerful language looking at the list of firsts that came with Lisp, it's easy to see why many languages pale in comparison.

The way around the tenth rule is polyglot programming. Realizing that one language/framework is not the golden hammer. Then instead of creating a poor, ad hoc implementation of Lisp, you can just use Lisp.

5
  • 4
    Power and age are independent. It's really quite irrelevant how good or bad LISP was at the time of it's creation, it matters how it compares to languages today. The firsts are utterly unimportant.
    – DeadMG
    Feb 27, 2012 at 8:34
  • 2
    @DeadMG, these "firsts" are nothing compared to the things which have not been ported from Lisp to the other languages yet.
    – SK-logic
    Feb 27, 2012 at 8:46
  • 2
    @DeadMG, you're right. One of the things people love about Ruby after they start digging into it is the Metaprogramming aspect of it. Lisp has that built in. C# developers love LINQ (with good reason) and the implications that declarative programming has on concurrency. Lisp has that in spades. As systems become more complex, they become more about nodes reacting to messages and less about objects. Lisp starts there, most other languages have to tack it on either ad hoc (hence the rule) or through a framework (e.g. Biztalk, Tibco, etc). Feb 27, 2012 at 13:57
  • 2
    "instead of creating a poor, ad hoc implementation of Lisp, you can just use Lisp" but Morris's corollary means you are still using a poor, ad hoc implementation ;)
    – jk.
    Feb 27, 2012 at 14:50
  • 1
    Perfect sidenote to that entry "the entirety of hacker culture is often perceived as ha-ha-only-serious by hackers themselves; to take it either too lightly or too seriously marks a person as an outsider, a wannabee, or in larval stage." Feb 27, 2012 at 16:54
10

Greenspun's "tenth rule" was an off-the-cuff bit of snark. When stretched far enough, if you make it cover "any scripting or configuration system," then obviously the answer to this question will have to be "yes," since configuration is something that any non-trivial program requires in some degree, and scripting is only slightly less common as you move up the complexity scale.

On the other hand, have a look at GOAL, a Lisp variant invented by Naughty Dog for game programming. It doesn't look much like "classic" Lisp at all. It's a highly imperative-style system, with object-oriented functionality, no interpreter, minimal support for garbage collection (relying on runtime-level cleanup facilities instead), and extensive support for inline assembly.

In other words, when they tried to use Lisp for a sufficiently complex project, they found that to do anything useful they had to turn the language into an ad-hoc, informally specified implementation of half of C++! ;) (And they eventually had to stop using it after the guy who designed GOAL left, because no one could understand his code.)

2
  • I guess my question is about specific parts of a large system. Eventually, the system will have parts that are better coded in another language due to the thought processes or techniques involved in using that language, rather than inherent speed or superiority. Mr. Lenaghan's story is one example. Mar 1, 2012 at 22:40
  • 2
    Actually, they stopped using GOAL because they got bought by company whose codebase was in C++. Also, GOAL was quite the lisp. Don't assume lowest-denominator online tutorials and university lectures are correct :)
    – p_l
    Oct 7, 2012 at 22:36
10

Curiously, one answer to this question is already in Programmers SE.

To quote the relevant part:

Greenspun's point was (in part) that many complex programs have built-in interpreters. Rather than building an interpreter into a language he suggested it might make more sense to use a language like Lisp that already has an interpreter (or compiler) built-in.

At the time I had been working on a rather big app that performed user-defined calculations using a custom interpreter for a custom language. I decided to try re-writing its core in Lisp as a large-scale experiment.

It took roughly six weeks. The original code was ~100,000 lines of Delphi (a Pascal variant). In Lisp that was reduced to ~10,000 lines. Even more surprising, though, was the fact that the Lisp engine was 3-6 times faster. And keep in mind that this was the work of a Lisp neophyte! That whole experience was quite an eye-opener for me; for the first time I saw the possibility of combining performance and expressiveness in a single language.
-- Michael Lenaghan

To further clarify that part, Michael responded to a comment with:

Wow, that must have been some really horrible Delphi code if it somehow managed to perform 3-6x slower than a Lisp implementation!" Right, I'll count that as my fail for not explaining it better. The Lisp implementation was able to transform user expressions into Lisp expressions--a trivially easy process--and then compile the Lisp expressions to native code (with full optimization). That's the meaning of Greenspun's Tenth Rule.
-– Michael Lenaghan

Given this answer is composed of someone else's answer elsewhere, it is community wiki.

3

Any sufficiently complex system will have domain specific concepts and requirements that are extremely hard to express with the abstractions of the language you are working in. This inadvertently forces programmers to create domain specific abstractions to ease the burden of bridging the semantic gap between the programming language and the specific domain. Once there are enough of these abstractions you basically have an interpreter of a domain specific language. This is an unavoidable part of software development.

2

The rule is a joke, but there is a bit of truth in it. Any complex system would contain a number of interpreted parts (see, how the "Interpreter pattern" is popular among those who believe in all that patterns mumbo-jumbo). Any complex system must provide some means of configuration, often structured, often interpreted.

Any complex system is very likely to have several code generation passes and various customised preprocessors in its build process (think of the things like moc in Qt or tablegen in LLVM).

Many systems are juggling the complex tree-like data-structures using set of (almost always) poorly designed tree walking and transforming tools closely resembling the library functionality from Common Lisp.

All these things comes for free with Lisp, and in most cases all that ad hoc, unplanned, not thought through thoroughly enough implementations would be utterly inferior.

1

The rule could probably be more accurately (and less amusingly) as "every large software based system will be required to implement dynamic behavior".

This can be done in two ways-

  1. A large complex configuration file with dozens of parameter and hundreds of definitions.

  2. An AD-HOC script language.

"sendmail" is probably the canonical example of type "1". I cannot think of any good examples of type "2" that do not involve embedding a "real" scripting language a la Warcraft/LUA or even Netscape/Javascript.

The problem is for a few parameters its quick and simple to do it with a config file, but, this solution does not really scale. However at no point will it be economical to dump the config file in favour of a script approach when adding one or two options to the config file. So the code that interprets the config file just ends up being a really badly written interpreter.

0

That may be true, as others stated, many programs require configurability and so do contain various lisp-like interpreters.

However the statement also implies with a smirk that all you need to make a program is Lisp, and that all other languages are inferior to it.

But it's wrong, Lisp may be expressive, but it's also too abstract, it tries to hide details of a platform and pretend nothing but lists exist in computer world.

The reality of high performance programming, is that sometimes we do need to mingle with bits and bytes, and do OS specific stuff, so it's not possible to do everything with just Lisp as statement implies.

It is rather the other way around, no matter how complicated, clever or sophisticated of a language you invent, all it ends up being is just another way to write assembly.

2
  • Seems like relevant only to the most ancient lisp environments of late 50s. Personally, I found Common Lisp's functions for dealing with bits probably one of the best (with main competition being Erlang). Arrays, hashtables, structs are all common.
    – p_l
    Oct 7, 2012 at 22:33
  • Its easy to write compilers for Lisp as you don't need to parse it. Lisp functions could be made and a macro compiler (which is just like the Lisp evaluator only one to half a page of code at the start) that turns those List expressions into C, and you are writing in C in Lisp but with all the power of macros, and lambda calculus if you want.
    – aoeu256
    Aug 4, 2019 at 22:08
0

Whether or not it was meant to be taken seriously, it is true of the largest C and C++ projects I have worked on.

What is not true is that the custom scripting languages resemble Common Lisp. The positive examples resemble Scheme (because the smarter designers integrated Guile, SpiderMonkey and Lua instead of inventing their own language.) The most DailyWTF-worthy examples were a Forth-like language and a MUMPS-like language.

Another example (not sure if it counts as Greenspunning, but certainly a WTF) was an XSLT interpreter used for general-purpose scripting. This was more Lisp-like as they added a feedback loop where the output would be XSLT-transformed a second time - so now you effectively have macros.
The motive here though was not to get access to lispy features but to sidestep the company's code QA procedures (which added 3 weeks of latency to every bug fix. XML was considered "data" and exempt from the process.)

-1

Unfortunately not!

While its best to just embed a real lisp(y) interpreter (javascript or lua alos does a fine job), adding a homebrew 4gl to a project reduces the overall size while increasing the flexibility.

Projects which "code everything" have vastly bigger module counts and become unwieldy and inflexible.

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