Saturday, December 08, 2007

Thoughts on Lisp: Things other languages took from Lisp

Lisp has a lot of features that I really like. A number of them have crossed over into modern mainstream languages, e.g. Java, Perl, Python, Ruby, and JavaScript. Some of these features definitely appeared first in Lisp. John McCarthy's History of Lisp paper captures several of those. Other features may have been adopted by Lisp from other languages, but certainly Lisp had them before any other language currently in wide use.

Here are several features of Lisp which I really like, and which have crossed over into modern, mainstream programming languages:

  • Conditional expressions. (Not to be confused with conditional statements!) McCarthy invented these for Lisp, but now they've spread to every language. For C developers, these are expressions using the

    (test ? consequent: alternate)

    form. For Lisp developers, it's just anything using IF.

  • Garbage collection. The concept of garbage collection preceded Lisp, but was implemented in individual application. Lisp was the first programming language to support GC directly. Nowadays, every mainstream language newer than C++ has GC too. And I hear that even the C++ community has been talking about ways to fit it into the language someday.

  • Bounds-checked arrays. I don't know where this actually appeared first. I do know that Lisp has had it for a very long time. All the post-C++ mainstream languages have this now, too.

  • Interactive development via the "Read-Eval-Print Loop" (REPL). These days, developers using Python, Ruby, and even Java (via Eclipse) enjoy the benefits of interactive development.

  • Lexical scope by default (Scheme and Common Lisp, not Emacs Lisp.) Lexical scope makes possible for the reader of a program's text to figure out where each value comes from. This is an immense aid to human readability, and to static introspection such that as performed by IDEs. Most modern languages use lexical scoping most of the time, although there are certainly ways to use other scopes in, e.g., Perl.

  • Closures. When what you really want is a callback, a closure is sometimes far more elegant than, say, an object implementing a single method. Closures have crossed over, but the depth of support varies considerably. Perl and Ruby have full closure support. Python lets a closure refer to, but not modify, a lexically-closed-over value. As Dan Weinreb noted just today, Java only has anonymous objects, which are weak substitutes for real closures because they can only refer to 'final' lexically-closed-over values.

I'm sure I've missed more positive features that have crossed over from Lisp to modern languages. Please mention those in the comments. If you know (more of) the history of any particular feature --- and in particular, if you can provide references --- please add a comment as well!

One more assumption

Extending the list of my assumptions and prejudices (perhaps I should have called them values?) in this post, here's one more::

  1. Encapsulation is good. It should be exceedingly difficult, if not downright impossible, to reach into the guts of a complex abstraction and fiddle with it.

On typing (poh-tay-toh) and typing (poh-tah-toh)

One often-heard statement about Lisp is that it requires much less code (that is, less typing) to get something done than Java. I wonder what percentage of that is because everything is done with one type: the pair. More typing requires more typing, as it were.

Does this fit with people's practical experience? How does it fit with other comparison points, e.g. Python?

Coming up next...

Things I like in Lisp that still haven't crossed over