Mark J. Dulcey
Tue, 24 Mar 1998 23:17:25 -0500
J. Han wrote:
> To Old Timers:
> What is it like using a Lisp Machine?
Background: I hacked at the AI Lab for a while, and then went to
work for LMI (Lisp Machine, Inc., the main competitor of
Symbolics back in the mid-1980s).
So what was special about a Lisp Machine?
There were a few things that were quite special then, but less so
now. A full-page bitmap display (monochrome; color LispM displays
existed but were rare) that was big enough to show a whole
printed page worth of text. A full-blown windowing system.
Multitasking and quick switching between programs. Virtual memory
so you didn't have to worry about running out of space. A
keyboard with enough keys to make the Emacs-like editor really
sing. (Modern PC keyboards don't have quite as many keys as a
LispM keyboard, but they have a lot more than typical terminal
keyboards of the early 80s did.) An interface to a laser printer,
so you could print out your stuff with lots of fonts and stuff.
Now on to the things that really made it special.
First, the main program listener (the LispM equivalent of a
shell) was Lisp. No second language to learn for interaction and
scripting; Lisp did it all. You had the full power of your
favorite language available right there at the prompt.
Second, it came with an editor (ZMacs, an Emacs-like editor
written in Lisp) that really understood the language, and was
fully integrated with the environment. Since the system also had
a full bitmapped display, and the editor understood multiple
typefaces, you could do a few tricks that Emacs can't on most
platforms, including my favorite - Electric Font Lock Mode. (It
automatically changed Lisp comments to a different typeface when
you typed in your code.)
Third, the compiler was nicely integrated with the editor. ZMacs
understood what parts of your buffers had changed, and recompiled
only the relevant pieces of code, so test/fix/recompile cycles
were VERY fast. (And unlike most programming environments, you
really did only need to recompile the functions that changed, for
reasons I will detail later.)
Fourth, the Lisp debugger was fully integrated and available
anywhere. Error at the "shell" prompt? Hit a bug in the editor?
Just want to break into the middle of the operation of some
program and find out how it works? You could be right there with
the same tools that you used to debug everything else. And all
the source code (on the LMI systems, ALL the source code, all the
way down to the microcode! Symbolics was a bit stingier, and
didn't distribute the microcode source.) was available online,
and functions were tagged with the path of the file they came
from, so the editor could find you the source of ANYTHING. (In
the early days, this was really important, because the
documentation was seriously lacking, so sometimes the only you
could figure out how to do something was to read the source of a
program that already did it.)
Fifth, it had a nice object inspector. And since the LispM was a
tagged-pointer architecture (every object had an associated type
code), the debugger ALWAYS knew exactly what you were looking at;
confusion caused by wild pointers, as is common in other computer
languages, was impossible.
Sixth - this one takes a bit of explaining. I mentioned earlier
that testing cycles were fast because you only had to recompile
the parts of your program that actually changed. The LispM was
special in this regard because it never snapped links. (Those of
you who have never studed Lisp implementation technique are
probably saying "Huh?" right now. Bear with me.)
When compiled code is loaded, it contains references to other
functions. Somewhere along the way, you have to turn these into
real jumps into the code of the other function (known as
"snapping links"). There are various strategies for doing that.
The traditional way was to resolve all the jumps as soon as you
load the code into memory. There are some economies of scale
doing it all at once, and you don't need to have the linker in
memory all the time. On the other hand, you waste time resolving
calls that never happen (code that doesn't get exercised), and
you can't change any of the code in the file without reloading
all of it.
More modern system with dynamic linking wait until the call
actually happens. The first time a function calls some other
function, the placeholder for the jump is replaced with a real
jump instruction by the dynamic linker. From then on, that
particular jump is hard-coded to its destination, and will
continue to call the same code object even if you recompile and
reload the called function. You don't waste time on calls that
never get exercised; you may not even have to load some of the
called code into memory at all (if the calls never happen). On
the downside, you have to have the linker present all the time.
In any case, Windows DLLs and Unix shared libraries both use this
The LispM followed the extreme strategy of NEVER snapping links.
Instead, it looked in the function value cell of the called
symbol on every call. There was some cost to this (an extra
memory reference on every function call), but it meant that you
could easily replace single functions from any source and
instantly change the behavior of the system. Of course, this
capability was also dangerous; if you replaced some basic system
function, you could completely break your system.
There was a limit to how much havoc you could wreak, though. Many
of the more basic functions were microcoded. When you compiled
your program, the code didn't contain normal calls to those
functions at all; it contained instructions that invoked the
microcode. So redefining really basic stuff like "car" wouldn't
have much effect - only code run in the interpreter would ever
use your new version. (This was true even if you recompiled
something AFTER redefining the function, by the way; the compiler
didn't bother to notice your redefinition.)
Finally, the LispM was thoroughly network-aware, back at a time
when that was rare. It could communicate with multiple types of
filesystem hosts (TOPS-20, Unix, VMS, a few different flavors of
LispM-based file servers, and so on) over an Ethernet (well,
originally a Chaosnet, an MIT-developed Ethernet-like network -
later, a real Ethernet), and could automatically reestablish
connections with systems if necessary (a trick that Windows and
the Macintosh STILL can't manage). It had Telnet and FTP
applications and a mail reader (ZMail, an offshoot of ZMacs with
lots of special goodies for mail reading - no relation to the
currently available product of the same name for PCs), so you
could do all your favorite Internet stuff.
Bottom line: I still miss working with the LispM. I have not yet
seen another environment that can measure up to it as a fast
Mark Dulcey firstname.lastname@example.org
Visit my house's home page: http://www.ziplink.net/~mark/buttery/