Xref: utzoo comp.lang.lisp:3657 comp.lang.scheme:1670 Path: utzoo!attcan!uunet!decwrl!apple!bionet!arisia!roo!masinter From: masinter@parc.xerox.com (Larry Masinter) Newsgroups: comp.lang.lisp,comp.lang.scheme Subject: Re: Virtues of Lisp syntax Message-ID: Date: 15 Sep 90 09:03:47 GMT References: <3368@skye.ed.ac.uk> <3407@skye.ed.ac.uk> <20301@well.sf.ca.us> Sender: news@parc.xerox.com Followup-To: comp.lang.lisp Organization: Xerox PARC, Palo Alto, CA Lines: 191 In-reply-to: jjacobs@well.sf.ca.us's message of 14 Sep 90 19:06:08 GMT (This may sound a little like a flame, but I don't mean it to be. Just comparing my recollection of History to Mr. Jacobs.) In article <20301@well.sf.ca.us> jjacobs@well.sf.ca.us (Jeffrey Jacobs) writes: >Having watched the LISP Syntax thread for a while, I thought a little >history might be in order... >Way back in the old days, development in LISP and the underlying >philosophy of the language were substantially different. >LISP was an interpreted language. Debugging and development was done in >interpreted mode; compilation was considered the *last* step in the >development process. *Way* back in the old days, Lisp was batch. Punch cards & JCL. Although the first generation (Lisp 1.5 on 7040 and its ilk) may have been primarily interpreted, mmost of the second generation Lisps were compiled (I think I remember that in Stanford's Lisp/360 the DEFINE function invoked the compiler.) After all, since it was batch (or interactive batch) you might as well compile. >LISP had two fundamental data types, CONS cells and ATOMs. ATOMs were >"indivisible", and included "interned symbols", numbers and strings. >(Arrays were added, but were less important to the underlying >concept). BBN Lisp had strings and arrays hash tables and a few other data types in the early 70's, and I don't think it was unique. Lisp 1.5 only had a few datatypes, though. >A key aspect of the language was the "equivalence of data and (source)code", >i.e. code consisted of LISP stuctures, which could be manipulated *exactly* >like any other LISP structure. Note that this is substantially >different from the modern view, where "functions (*not* code) are a data >_type_" and not directly modifiable, e.g. even "interpreted" code in >most modern implementations >gets converted to something other than a CONS based structure. I think the move toward clearly distinguishing between functions and lists that denote functions is positive. It just means that there is a one-way transformation, not two-way. >This "equivalence" allowed some very interesting capabilities that are >no longer available in modern implementations. Since the interpreter >operated on list structures, it was possible to dynamically modify code >while in the process of execution. Now, most of us didn't write >self-modifying code (although we probably all tried it at least once). >But we were able to stop an execution, and make changes to code and >continue from the breakpoint without having to recompile or start over. >We could issue a break, put a trace point around an expression *within* >a defined function, and continue. Or we could fix it, and continue; >the "fix" would be propagated even to pending calls. E.g. if you >had >(DEFUN FOO (X Y) > expr1 > expr2 > ...) >and expr1 invoked FOO recursively, you could break the execution, >change expr2 (or TRACE it, or BREAK it or...), all of the pending >invocations on the stack were affected. (You can't do this with >compiled code). Unfortunately, it was also impossible to avoid some fairly problematic situations, e.g., (defun foo (x y) expr1 expr2 ...) if you deleted, added, or renamed an argument, you might start executing code where the variable bindings of the old stack frame didn't match what the new code expeced. [As a side note, many learning LISP programmers frequently do encounter self-modifying code and are mystified by it, e.g., (let ((var '(a b c))) ... (nconc var value)) ] >It allowed things like structure editors (where you didn't need to >worry about messing up parends), DWIM, and other features that have >been lost in the pursuit of performance. Medley has a structure editor which works fine in a compile-only mode (compile & install when done editing the structure.) I don't think there's a very strong correlation between compilation and structure editing. As for dynamic error correction, insertion of breakpoints and trace points, however, the major impediment is not that Lisp is compiled: the major problem is the presence of *MACROS* in the language. (defun stopme () (macrolet ((nothing (&rest ignore) nil)) (nothing (try to insert a (breakpoint) in here somewhere)))) Macros can cause the executed code to look completely different than the original source; this plays havoc with most source-level debugging techniques. >With this view (and combined with the mathematical purity/simplicity >of McCarthy's original concept) LISP syntax not only makes sense, >it is virtually mandatory! Certainly you could take Lisp, print it backward, use indentation instead of parens and *completely* change the way the language looks as a sequence of characters and still wind up with the same features. As long as there's an invertable relation between the printed representation and the internal structure, you could still use structure editors and do error correction, etc. >Of course, it also effectively mandated dynamic scoping. "Local"/lexical >scoping really came about as the default for the compiler primarily because >most well written LISP code didn't use function arguments as free/special >variables, so it was an obvious optimization. However, several years >ago, Daryle Lewis confided in me that he had intended that UCI LISP be >released with the compiler default set to everything being SPECIAL. >Given the historical problems in reconciling local and free variables, >and the fact that the vast majority of LISPers who learned the language >in the '70s and early '80 learned UCI LISP, I can't help but wonder >if what affect this might have had on Common LISP... The Interlisp compiler always had the compiler default that all variables are SPECIAL. (Daryle moved on to BBN and worked on the BBN-Lisp compiler with Alice Hartley.) I don't really know the demographics, but my impression was that the popular Lisp implementations of the '70s were MacLisp, Lisp 1.6, Franz Lisp, Interlisp, and that UCI Lisp wasn't so widely used. Maybe the distinction is between the research vs. the student community. >(FWIW, REDUCE was originally done in UCI LISP way back in the early '70s, >and BBN/INTERLISP supported MLISP, an Algol like syntax. Seems to me that >RLISP must go back that far as well. Given that structure editors are >incredibly ancient, I wonder why the people at Utah didn't use one of >those. Oh, and almost nobody ever learned LISP using 1.5... I'm not sure about the REDUCE bit, although it doesn't ring true (my 'standard lisp' history is a bit rusty), but you certainly shouldn't confuse MLISP (which is the meta-lisp used in McCarthy's books) with CLISP (which is the DWIM-based support for infix notation that was added to Interlisp in the mid-70s.) I'm not sure what editor Griss and Hearn used for REDUCE, but I'd guess it was some variant of TECO. Remember that in the early 70's, people still actually used teletype machines and paper-based terminals to talk to computers; neither text or structure based editors actually let you *see* anything unless you asked it to print it out for you. > Personally, I think the whole reason LISP machines were created > was so that people could run EMACS :-) I believe EMACS predated LISP machines by some margin; besides, Eine Is Not Emacs. >However, if compilation is the primary development strategy (which it >is with CL), then the LISP syntax is not particularly useful. Modern >block structured syntax is much easier to read and maintain; it also >allows constructs such as type declarations, etc. to be much >more readable. Infix notation is indeed much more familiar to most >people. Keyword syntax in most languages is much more obvious, readable >and certainly less prone to errors and abuse than CL. The elimination >of direct interpretation of structures (as read) and the almost total use >of text editors does indeed leave LISP syntax a relic from the past. The ability to write programs that create or analyze other programs without resorting to extensive string manipulation or pattern matching has always been a strength of Lisp, whether or not you can do so on the fly with programs that are running on the stack. I guess C doesn't have a 'Modern block structured syntax' (I certainly get cross-eyed looking at some of the constructs that cross my screen); perhaps it is a relic from the past, too. Certainly there are languages with a more principled syntax (Prolog, Smalltalk). I think HyperTalk is fairly easy to read even though it is pretty inconsistent about how it does nesting. I think a lot of people find Lisp hard to read and maintain, and that the difficulty is intrinsic, but I don't think there is as strong a correlation with editor technology as you imply. -- Larry Masinter (masinter@parc.xerox.com) Xerox Palo Alto Research Center (PARC) 3333 Coyote Hill Road; Palo Alto, CA USA 94304 Fax: (415) 494-4333