> 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

Reply via email to