There are no shortage of vague "Scheme vs Common Lisp" questions on both StackOverflow and on this site, so I want to make this one more focused. The question is for people who have coded in both languages:

While coding in Scheme, what specific elements of your Common Lisp coding experience did you miss most? Or, inversely, while coding in Common Lisp, what did you miss from coding in Scheme?

I don't necessarily mean just language features. The following are all valid things to miss, as far as the question is concerned:


Specific libraries.
Specific features of development environments like SLIME, DrRacket, etc.
Features of particular implementations, like Gambit's ability to write blocks of C code directly into your Scheme source.
And of course, language features.


Examples of the sort of answers I'm hoping for:


"I was trying to implement X in Common Lisp, and if I had Scheme's first-class continuations, I totally would've just done Y, but instead I had to do Z, which was more of a pain." 
"Scripting the build process in my Scheme project got increasingly painful as my source tree grew and I linked in more and more C libraries. For my next project, I moved back to Common Lisp."
"I have a large existing C++ codebase, and for me, being able to embed C++ calls directly in my Gambit Scheme code was totally worth any shortcomings that Scheme may have vs Common Lisp, even including lack of SWIG support."


So, I'm hoping for war stories, rather than general sentiments like "Scheme is a simpler language" etc.

My undergrad degree was in Cognitive Science and Artificial Intelligence. From that I had a one-course intro to Lisp. I thought the language was interesting (as in "elegant") but didn't really think much of it until I came across Greenspun's Tenth Rule much later:


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


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.

Some time later when I started working on a web-based project I auditioned a number of languages. I included Lisp and Scheme in the mix. In the end I selected a Scheme implementation--Chez Scheme. I've been very happy with the results.

The web-based project is a high-performance "selection engine". We use Scheme in a number of different ways, from processing data to querying data to page generation. In many spots we actually started off with a different language but ended up migrating to Scheme for reasons I'll describe briefly below.

Now I can answer your question (at least in part).

During the audition we looked at a variety of Lisp and Scheme implementations. On the Lisp side we looked at (I believe) Allegro CL, CMUCL, SBCL and LispWorks. On the Scheme side we looked at (I believe) Bigloo, Chicken, Chez, Gambit. (The language selection was a long time ago; that's why I'm a bit hazy. I can dig up some notes if it's important.)

Right off the bat we were looking for a) native threads and b) Linux, Mac and Windows support. Those two conditions combined knocked everyone but (I think) Allegro and Chez out--so in order to continue the evaluation we had to loosen the multi-threading requirement.

We put together a suite of small programs and used them for evaluation and testing. That revealed a number of issues. For example: some implementations had defects that prevented some tests from running to completion; some implementations couldn't compile code at run-time; some implementations couldn't easily integrate run-time compiled code with pre-compiled code; some implementations had garbage collectors which were clearly better (or clearly worse) than the others'; etc.

For our needs only the three commercial implementations--Allegro, Chez and Lispworks--passed our primary tests. Of the three only Chez passed all tests with flying colors. At the time I think Lispworks didn't have native threads on any platform (I think they do now) and I think Allegro only had native threads on some platforms. Furthermore, Allegro had a "call us" run-time licensing fee which I didn't like very much. I believe Lispworks had no run-time fee and Chez had a straightforward (and very reasonable) arrangement (and it only kicked in if you used the compiler at run-time).

Having produced somewhat significant chunks of code in both Lisp and Scheme here are some compare and contrast points:


The Lisp environments are far more mature. You get a lot more bang for the buck. (Having said that, more code also equates to more bugs.)
The Lisp environments are far more difficult to learn. You need a lot more time to become proficient; Common Lisp is a huge language--and that's before you get to the libraries that the commercial implementations add on top of it. (Having said that, Scheme's syntax-case is far more subtle and complicated than any one thing in Lisp.)
The Lisp environments can be somewhat more difficult to produce binaries in. You need to "shake" your image to remove unneeded bits, and if you don't exercise your program correctly during that process you could end up with run-time errors later on. By contrast, with Chez we compile a top-level file that includes all of the other files it needs and we're done.


I said before that we ended up using Scheme in a number of places we didn't originally intend to. Why? I can think of three reasons off the top of my head.

First, we learned to trust Chez (and its developer, Cadence). We asked a lot from the tool, and it consistently delivered. For example, Chez has historically had a trivially small number of defects, and its memory manager has been very, very good.

Second, we learned to love the performance we got from Chez. We were using something that felt like a scripting language--and we were getting native-code speed from it. For some things that didn't matter--but it never hurt, and sometimes it helped an awful lot.

Third, we learned to love the abstraction Scheme could provide. I don't just mean macros, by the way; I mean things like closures, lambdas, tail-calls, etc. Once you start thinking in those terms other languages seem rather limited by comparison.

Is Scheme perfect? No; it's a trade-off. First, it allows individual developers to be more effective--but it's more difficult for developers to grok each other's code because the signposts that most languages have (e.g., for loops) are missing in Scheme (e.g., there are a million ways to do a for loop). Second, there's a much smaller pool of developers to talk to, hire from, borrow from, etc.

To sum it up, I think I'd say: Lisp and Scheme offer some capabilities not widely available anywhere else. That capability is a trade-off, so it had better be one that makes sense in your particular case. In our case the determining factors between whether to go with Lisp or Scheme had more to do with very fundamental features (platform support, platform threads, run-time compilation, run-time licensing) than they did with language or library features. Again, in our case that too was a trade-off: with Chez we got the core features we wanted but we lost the extensive libraries the commercial Lisp environments had.

Also, just to reiterate: we looked at the various Lisps and Schemes a long time ago; they've all evolved and improved since.
