> If I remember correctly, the other Lisps I've used (Allegro, > Lispworks, Genera) only give warnings for this when you compile a > form. You don't get warnings like this when typing in something to > the listener/interpreter. They have a friendlier, more approachable > feel because of it.
The above Lisps do *NOT* declare special these variables that are "created" with setf at the top level. Here's the way I understand it. Using setf at the top level has traditionally been allowed. In ANSI CL it's undefined behavior, which means it is allowed to do things like incinerating the planet and so on. But because it is traditional, most Lisps not only allow it but try very hard not to incinerate the planet after you type it. The question then arises, "Having decided not to incinerate the planet, what do we do instead?" Most Lisps create a symbol, and set its value, but aren't particularly happy about it. You wind up with a sort of bastardized global variable of the C world stripe, but you still get compiler warnings. Here is an example of Allegro CL: CL-USER(1): (defun baz () (print foo)) BAZ CL-USER(2): (defun bar () (let ((foo 3)) (baz))) BAR CL-USER(3): (setf foo 2) 2 CL-USER(4): (bar) 2 2 CL-USER(5): Here's what happens when you compile: CL-USER(5): (compile 'bar) ; While compiling BAR: Warning: Variable FOO is never used. BAR T NIL CL-USER(6): (compile 'baz) ; While compiling BAZ: Warning: Free reference to undeclared variable FOO assumed special. BAZ T T CL-USER(7): (bar) 2 2 CL-USER(8): (describe 'foo) FOO is a SYMBOL. Its value is 2 It is INTERNAL in the COMMON-LISP-USER package. CL-USER(9): I would say that the above can be quite confusing to a newbie. Now CMUCL does something different. It assumes that when you type (setf foo 2) you meant to type (defvar foo 2) or (defparameter foo 2) but got lazy. So it does something that might be closer to what experienced Lisp programmers want, while chiding you for your laziness. In effect, CMUCL says that setf at the top level has the same semantics as defparameter, but gives a warning. * (defun baz () (print foo)) BAZ * (defun bar () (let ((foo 3)) (baz))) BAR * (setf foo 2) Warning: Declaring FOO special. 2 * (bar) 3 3 * (compile 'bar) ; Compiling LAMBDA NIL: ; Compiling Top-Level Form: BAR NIL NIL * (compile 'baz) ; Compiling LAMBDA NIL: ; Compiling Top-Level Form: BAZ NIL NIL * (baz) 2 2 * (bar) 3 3 * Surely this is preferable to incinerating the planet. I'm not willing to die in the trenches over whether CMUCL should keep doing what it does, but I would maintain that it's more conducive in the long run to a proper Lisp style than doing what the other Lisps do. Note that Scheme, on the other hand, doesn't even allow this kind of thing: 1 ]=> (define x 3) ;Value: x 1 ]=> (set! x 4) ;Value: 3 1 ]=> (set! y 5) ;Unbound variable: y ;To continue, call RESTART with an option number: ; (RESTART 2) => Define y to a given value. ; (RESTART 1) => Return to read-eval-print level 1. 2 error> I suppose this is also preferable to incinerating the planet, but it has a kind of pedantic feel that Lisp doesn't have. -- Fred Gilham [EMAIL PROTECTED] The rage of dance and style that swept the country in the late '70s crumbled from serious backlash as disco freaks seemed to finally wake up and realize what they were wearing. -- Michael Okwu
