Posted 2010-05-14 22:00:00 GMT

Lisp's (and especially Scheme's) greatness is its coherence — instead of expressions, statements, sequence points and so on, it just has expressions. In implementations, instead of separate tools for compiler, debugger, profiler, you generally have one tool and, if you have the source, can in a unified way examine and fluidly adapt any part. This is never going to fly in the Balkanized world of other languages, where the compiler is generally not implemented in the language itself.

Mainstream languages like JavaScript, Python, C#, C++ and Java have steadily adopted some of Lisp's ideas (e.g. garbage collection (1959)), but some, sadly, remain overlooked. Having moved back to programming in C++ and doing some C#, I'm constantly amazed that some really fundamental things from Lisp remain shrouded in mysterious brackets.

1. In my opinion, most basic and most overlooked are the benefits of usable global variables. In Lisp you don't have to keep passing extra parameters to functions because a function they call needs them. Each special variable has its own stack (per-thread in most implementations, leading to performance compromises). So you can use global variables without worrying about affecting other contexts.

Historically, lexical scoping is relatively new to Lisp (last thirty years?), and as it is much cleaner as a default, old Lisp's dynamic or special scoping received a bad name. But in the right places it makes the difference between having to add a parameter to a chain of function calls or adding an unnecessary field to a class, and simply implementing the needed functionality.

2. The condition system by Kent Pitman is utterly fantastic. C++'s STL is vastly better thought out than Common Lisp's sequences; but the conditions system in Common Lisp is a leap ahead of C++'s exceptions. Instead of an exception automatically unwinding the stack, callers can choose to catch a specific exception (called a condition) and perform some action — like, say, popping up a dialog box asking the user to free up disk space and retry — all without affecting the control flow. You're free to unwind the stack if you like of course. In implementation, this is normally pretty much a library on top of the language using special variables and closures. . .

3. Which brings me on to powerful closures. C++ is getting lambda functions, but they're not as powerful as Common Lisp's. Python resists allowing you to modify variables in the enclosing scope. In a Common Lisp lambda, you can not only modify variables in your enclosing lexical scope, but also return-from the enclosing scope (provided of course that it's still on the stack). This can be implemented by an exception with a tag unique to the enclosing function in C++ and other languages. But it is immensely useful, and much more convenient to have the compiler insert the boilerplate for you, as it allows all sorts of things.

It would be great if some these ideas would be massaged into other languages.