From: Brian of ASTD-CP
Subject: I was a teenage C programmer
Date: 
Message-ID: <1991Jan18.184354.19666@jato.jpl.nasa.gov>
Then I found Lisp (& Scheme & T) and everlasting happiness...

Just my $0.02 worth on the "Lisp is living/dying" thread.  

After 12 years of using C for *all* my software (I do CS and
astrophysics: operating systems, interactive graphics,
computer-human interfaces, etc.  etc.), I discovered Scheme by
pure accident (I bought Abelson & Sussman's book on a lark and
stumbled on Betz's XScheme PD compiler), and have used Common
Lisp & T as well.  Here's how I use these tools.

* I use Common Lisp for experimental programming --- that is
  designing software; basically "figuring out what I want
  to do" and "figuring out how to do it".  Result is an "exe-
  cutable design document."  I use CL rather than Scheme or T
  just because it's a little easier for me to procure it on
  most platforms.

  Common Lisp is helpful for the following reasons (in priority
  order)

  -- The language of the programming environment is the same
     as the language of the program.  Not true with Unix/csh
     and C.  I have found that *anything* you want to do in a
     program you will ultimately want to do interactively in
     the programming environment, and vice versa.  Interactive
     grep leads to the need to grep from a program, & so on.
     It's a big headache to do in C/UNIX/csh; basically you end
     with two versions of every interesting function, a
     C-callable one and a csh-callable one.  This comes for
     free in almost all Lisp implementations.

  -- dynamic and recursive structures are really easy in all
     dialects of Lisp, and they're a big, recurrent headache 
     in C.  These structures are necessary for most interesting
     software (arrays are just not good enough).

  -- testing is easy because generic read / eval / print are
     built in.  In C, you have to write special purpose read,
     eval, and print routines for every data type and every
     function.

  -- being able to create procedures at runtime with lambda is
     a big win and lets me do certain things that are impossible
     in C without implementing a "lambda calculator," which I 
     had done several times in the past, each time a little 
     differently for various, extrinsic reasons.  

  -- programs can be stored in data files and interpreted at
     runtime.  I call this "scripting", which may not be an
     accepted term for it (remember, I was a teenage C
     programmer).  Most interesting application programs need
     scripting capability, and I've implemented it dozens of
     times in C, each time a little better and a little cleaner
     as I learned more.  Lisp is, among other things, the
     ultimate, all-purpose, extensible, tailorable scripting
     language, and thus is the asymptote of my many years of C
     development.

  -- automatic memory management

  -- lots of mundane, ordinary, well-understood data types come
     for free: complex numbers, lists, strings, hash tables, 
     etc.  In C, I have to reinvent these things over and over
     again.  

* For portability, which is *very important* to me, when I 
  actually "do it", after figuring out "what to do" and "how
  to do it", I probably use C, with the following 
  provisos:

  -- If it's a small application (defined, by me, as one that
     doesn't need an embedded scripting language), I'll write the
     whole thing in C or contract it out to a C programmer using
     the CL code as design document.  

  -- If it's a big application, which means it needs a
     scripting language.  then I'll start with a simple-scheme
     interpreter (just the basics, Ma'am) written in super
     portable C.  XScheme is my current favorite.  I'll design
     an "application language," in which the application can be
     conveniently written, and implement the primitives of this
     new language in C and Scheme, but so they can all be
     called from Scheme.  I implement performance-critical
     primitives, i.e. those that must conserve space or time,
     in C.  I implement structure-critical primitives, i.e.
     those that are complex or otherwise challenging from a
     structural point of view, in Scheme.  If I've designed the
     "application language" correctly, then the final
     application is implemented as a short script written in
     the application language.  Usually, the script is just a
     sequence of commands in the application language, though
     occasionally loops and conditionals may show up.

That's how I program nowadays.  

brian
 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 . . Brian Beckman . . . . . . . . . . ·····@granite.jpl.nasa.gov. . . .
 . . meta-disclaimer: every statement in this message is false . . . . .
 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .