Subject: Re: Harlequin vs. Allegro
From: Erik Naggum <>
Date: 1998/06/24
Newsgroups: comp.lang.lisp
Message-ID: <>

* Zeno the Anonymous Poster
| the moment, is it possible to create a small application with Lisp which
| could be distributed over the web?

  yes, of course.  the question is: what does the recipient need to use it?
  for some languages, the user needs to have installed *huge* libraries of
  run-time support systems, a *massive* operating system, and have
  contributed a lot to Bill Gates's now 50 billion dollar fortune.  for
  other languages, the user needs to have installed libraries of run-time
  support systems, an operating system, and not have contributed to any
  top-20 fortune list.  that's the difference between VB and Common Lisp,
  for instance, and all you can really argue is "but I already have all the
  stuff for VB installed".  the question is then why you do that instead of
  the much more sensible thing, and perhaps why you should stop installing
  stuff now, just _before_ you get yourself a Common Lisp environment, too.

| Let's say, you wanted to create a small utility which would search the
| files on Win95/NT computers and find duplicates, then provide a list to
| the user allowing them to delete duplicate files as they see fit.  Can
| you do this with Lisp?  Can you do this with Allegro Common Lisp?  Are
| small utilities like these necessarily large programs because of the size
| of Lisp itself?

  yes, of course you can.  however, how do you run this utility?  with the
  VB approach, you basically run the huge run-time system from the command
  line or GUI environment and feed it some input that happens to be your
  "small utility".  with the Common Lisp approach, you basically run the
  Common Lisp environment, then invoke the function from the listener.
  (sufficiently advanced Lisp listeners are indistinguishable from GUI's.)

  Emacs users everywhere run some surprisingly large programs in Emacs and
  don't seem to have any craving for an "executable" version of, say, Gnus.
  the same applies to other Lisp software.  of course, you _can_ run a
  separate Emacs that you dumped with Gnus and argue against the size of
  the damn thing, but why bother?  running Gnus inside your already running
  Emacs is _easier_.  an that's the issue with Common Lisp, too: it's just
  a whole lot easier to have a Common Lisp environment running and then do
  all the cool stuff in it than to run whatever other environment your
  computer came with and fire up huge run-time systems every time you need
  the services of a small utility.

* Pierre Mai
| I hate repeating myself, but:
| 1) For very small, _self-contained_ utilities, Common Lisp may simply
|    not be the right language.

  I disagree profoundly.  first, "self-contained" is no longer a valid
  concept when used about general purpose computers like PC's or
  workstations -- the interdepencies between individual programs and the
  operating system environment has been so blurred as to make the choice
  between "data for the run-time system" and "executable program" all but
  meaningless.  second, I run self-contained utilities in Common Lisp all
  the time, if I may twist your words a little: I call them "functions".

|    On Unix you'd rather either use the built-in utilites, or perl/scsh.

  really?  if you consider perl and scsh "utilities" to be _small_, just
  because they fit in very small source files, I'm afraid that you really
  don't see the whole picture.  Common Lisp programs are easily shorter
  than Perl and Scheme programs, so I would imagine that if you could run
  Common Lisp programs with the hash-bang convention, they'd be even
  smaller than "very small", since you completely ignore the *enormous*
  costs of the Perl and Scheme Shell execution environment.

|    Another posibility are several Scheme implementations, which are
|    able to produce small stand-alone images...

  let me tease you a bit: do you mean images from which you can boot your
  computer, like form a floppy disk?  that is the truly "stand-alone"
  program.  dedicated software like Internet routers running on PC's meet
  this definition of "stand-alone", and they do exist -- they aren't even
  very hard to build -- all it takes is linking in the basic facilities
  from a library and asking the linker to write a slightly different file
  format that the boot loader recognizes.  matter of fact, the whole
  operating system meets this definition of "stand-alone".  (however, they
  aren't _small_, anymore, and frequently need more than one CD-ROM. :)
  incidentally, no Scheme implementations I know of can write such images.

|    Things look very different if you want the utility to work in CL,
|    as a utility for developers, since then the user already has a CL
|    environment, and you only distribute the (compiled) files.

  but the user _always_ "already has" the prerequisite environment!

  this actually reminds me of a user who sued an Internet provider over
  here because their marketing line for a "complete" package of software
  and hardware for Internet users, "all you need to use the Internet", was
  _entirely_ false -- you actually needed a whole _computer_ (and it had to
  pledge allegiance to Bill Gates to boot, but that didn't seem to worry
  anybody) and only _then_ did you have all you needed.

  if you don't have a Common Lisp environment, the question should _not_
  be: "how can we make our software available to users without computers?",
  but "how do we make them understand that they need a computer _with_ a
  Common Lisp environment?"

  the problem, then, is only selling them the first Common Lisp application
  that needs a Common Lisp environment.  once he's got it, it's just
  rolling them in!

| So this all boils down to using the right tools for the problem: Use CL
| where it works best: In medium[3] to large applications that work on
| complex data and/or implement complex functionality/logic.  CL is _not_
| the language of choice for small, stand-alone applications, which could
| even be implemented in perl or VB and still be maintainable.

  wrong!  this is _so_ wrong!  *cringe*  (uncringe, breathe.)

  nothing ever _starts_ large except in some extremely specialized areas.
  all over the place, you're expected to buy the large starting point and
  then make some small application on top of it, then get more funding and
  boss approval and peer recognition and all that, and _then_ you let the
  thousand cancers grow.  Perl is *huge*, VB is even bigger.  on top of
  these monsters, you can write a small program that does something useful.
  Common Lisp is not different in any possible regard, except it makes for
  smaller, more elegant, and more playable toys.  however, when Perl or VB
  code gets bigger than is good for them (a screenful in my opinion, but
  people seem to have very large screens these days), two things happen at
  once: (1) they realize they should have used a better language, and (2)
  they can't use a better language, for several reasons: (a) they don't
  know the better language because they have never started using it for
  small toys, (b) they don't have the better language available because
  they were encouraged to use Perl and VB for "small" applications and
  never got any experience with it, (c) they don't have the chutzpah to ask
  their boss for the better language that they don't know anything about
  because they didn't dare realize that their application would work on
  complex data and/or implement complex functionality/logic until just
  after they ran out of the chutzpah needed to say Perl or VB (and they)
  could handle it, (d) it means scrapping working code, and finally, (e)
  because the change to the better language is no longer incremental, like
  all the other changes to code they have worked on or written have been.

  what happens to a Common Lisp system that grows?  with a marginal amount
  of nurturing by people who care about elegance, it stays elegant, and it
  acquires functionality the same way that the Common Lisp language did: by
  careful consideration of the costs of changing one's ways as well as good
  design in general functionality where observed necessary.  I think a
  Common Lisp programmer who is able to think in the terms of Common Lisp
  the Standard (i.e, ANSI X3.226) and who is not afraid to write functions
  and macros and interfaces that need specification on the same level of
  precision as the standard facilities will necessarily write elegant code,
  and not end up with a hodge-podge of special-cased crud that fails to
  achieve abstraction by it's sheer lop-sided overweightness, which is what
  happens to the cancerously growing masses of code in languages that had
  all their abstraction done by the language designer and then you just get
  to use whatever they left you (C, C++, Perl, VB, etc, etc).

  my favorite examples of just this kind of development on top of Common
  Lisp are the MOP, the Gray Stream proposal, and logical pathnames (with
  which I've spent the last few days struggling...).  one could view CLOS
  as just such an extension to the first Common Lisp language.  their
  commonalities are: being well-integrated, solving very hard problems
  elegantly through abstraction in the right places, and exposing no
  essential differences between "application", "extension", and "language".
  properties like this is why I like Common Lisp over languages that make a
  tremendous effort to separate the three categories, and I want to write
  my code the same way, potentially leaving something of lasting value, not
  just some piece of code that "works".  what makes this both possible and
  impossible, however, is that adding to the Common Lisp heritage is not
  for random enthusiasts in the pre-burn-out phase, but for those who are
  willing to grok the language (if "grok" is still recognized as a word by
  our younger audience -- Merriam-Webster's Collegiate dropped it between
  the Ninth and the Tenth Edition -- boo hiss).  this takes a lot of time
  and effort and is a sometimes humbling experience, but there is also no
  shortage of people a lot smarter and more experienced than yourself who
  have gone before you.  (at least in my experience.)  making small steps
  in this way in Common Lisp has given me a lot more pleasure than most of
  the stuff I have ever been proud of in C or under Unix.

  in contrast, just about any newbie can make suggestions for (real and
  important) improvements to Perl or C++ and actually get them into the
  language!  knowing how cool it is to see "my feature" in a large system
  like Emacs, it's no wonder that Perl enthuiasts feel the way they do
  about their tools, but I contend that they would feel a _lot_ better if
  they had not had to invent the mindless kludges that made some trivial
  thing marginally easier, but could have used a well-functioning system
  from the start and could write some small piece of code that did
  something neatly and cleanly that would otherwise be _very_ ugly.

  my suggestion is simply: start with small problems, not with large ones.
  (and don't start with problems that you think are ideal for Perl or VB --
  you'll find that it was the language mindset that defined "ideal", not
  the problem itself or indeed _any_ part of its nature.)  the goal is to
  gain experience, just like you gained experience with Perl or VB: by
  doing little things that looked sufficiently fun.  don't think for a
  minute that "what's cool in Common Lisp is different from what's cool in
  Perl or VB", but ask "what's cool in _this language_?" (which is actually
  what you should think for any language, or tool, or system, or whatever).
  if you start off thinking "how will I solve this Perl problem in Common
  Lisp?" you will only find that the Perl mindset is your limitation, and
  you will probably blame Lisp, not the least because Larry Wall does.

  for your entertainment, a small piece of code that almost completely
  hides the annoying habit of at least one operating system to delimit
  lines in text files with CRuft instead of just newline characters, and
  for the moment ignoring the fact that this problem should have been
  solved even more elegantly by the file transfer/sharing software...

;;; administrivia
(defpackage "STREAM-EXAMPLE"
  (:use "COMMON-LISP"
	"STREAM"		;the Gray stream proposal
	"CLOS")			;the Meta-Object Protocol
  (:use whatever is appropriate))

(in-package :stream-example)

;;; a typical simple mixin filter class and methods.
(defclass macintosh () ())

(defmethod stream-write-char ((stream macintosh) (character (eql #\newline)))
  (call-next-method stream #\return))

(defmethod stream-read-char ((stream macintosh))
  (let ((character (call-next-method)))
    (if (char= character #\return)

;;; interface function to dynamic stream class creation
(defun push-mixin (mixin stream)
  "Push the MIXIN (named by a symbol) on STREAM (a stream object).
Actually, dynamically create, if necessary, a subclass of MIXIN and the
current class of STREAM, and change the class of STREAM to this class."
  (let* ((name (concatenate 'string
		 (symbol-name mixin) "+"
		 (symbol-name (type-of stream))))
	 (symbol (intern name #.*package*))
	 (class (or (find-class symbol nil)
		    (ensure-class symbol
		      :direct-superclasses (list mixin (class-of stream))))))
    (change-class stream class)))

;; typical usage
(with-open-file (stream "some-file-from-a-mac" :direction :input)
  (push-mixin 'macintosh stream)
  (read-line stream))

  I think this is pretty cool, not the least because I can string together
  all sorts of filter functions and mapping tables with mixin classes like
  this, bunch up a number of thus created streams in a broadcast stream and
  write to a whole bunch of files at once in places in the networked file
  system I have relegated to the logical pathname stuff to select for me.
  an 8,000-line piece of C code got replaced by 400 lines of Common Lisp in
  this fashion.  (yes, it's also faster. :)


PS: the other articles that need replying to will be answered shortly.
-- is about my spam protection scheme and how
  to guarantee that you reach me.  in brief: if you reply to a news article
  of mine, be sure to include an In-Reply-To or References header with the
  message-ID of that message in it.  otherwise, you need to read that page.