Path: utzoo!attcan!uunet!seismo!sundc!pitstop!robv From: robv@pitstop.UUCP (Rob Vollum) Newsgroups: comp.lang.lisp Subject: Re: SETQ vs DEFVAR at the top level Keywords: closure, HELP Message-ID: <141@pitstop.UUCP> Date: 1 Jul 88 14:21:56 GMT References: <4431@medusa.cs.purdue.edu> Reply-To: robv@pitstop.UUCP (Rob Vollum) Organization: Sun Microsystems, Inc., Lexington, MA Lines: 134 In article <4431@medusa.cs.purdue.edu> you write: > In Common Lisp, what difference does it make if one gives his >global variables lexical scope (via SETQ) or dynamic scope (via DEFVAR)? >None you say, only it is better style to use DEFVAR? WRONG bucko! There is plenty of difference, and I believe that the spec for Common Lisp makes the difference clear. DEFVAR will PROCLAIM a variable to be SPECIAL. That is, after DEFVARing a variable to be special, it may never be referenced in a truly lexical fashion ever again. (Perhaps you have some confusion over what "global" and "lexical" really mean. I reference your statement "give his global variables lexical scope". What exactly is that supposed to *mean*?) Ancilliary issues: DEFVAR will not reassign a value to a variable that is already defined. For example, try . (defvar *bloppo* 237) bloppo . (defvar *bloppo* 'a-new-value) *bloppo* . *bloppo* 237 SETQ, on the other hand, merrily assigns its value to its variable at any time, lexical or special. This, along with annotation to your example, should clear up your "mystery". > I define a queue as a closure: >(defstruct queue > get put ) >(defmacro get-q (q) > `(funcall (queue-get ,q))) >(defmacro put-q (q v) > `(funcall (queue-put ,q) ,v)) No matter what you think is happening below *q* is LEXICAL, not special. Wrapping *'s around a variable is a naming *convention*, and does nothing to make a variable special (global) or lexical. The closure over *q* is a lexical closure, as indicated. *head* and *tail* are similarly just "funny-named" lexicals. >(defun new-queue (size) > (let ((*q* (make-array size)) (*head* 0) (*tail* 0)) > (make-queue > :get (function > (lambda () > (unless (eql *head* *tail*) > (prog1 > (svref *q* *head*) > (when (= (incf *head*) size) (setq *head* 0)))))) > :put (function > (lambda (value) > (setf (svref *q* *tail*) value) > (when (= (incf *tail*) size) (setq *tail* 0) ) > (when (= *tail* *head*) (format t "~%Queue Overflowed~%") ) > value ) ) ) ) ) > I start with a clean environment and evaluate OR compile the above code. > I then have the following interaction with LISP: >-> (setq aq (new-queue 5)) >#S(QUEUE :GET # :PUT # ) > I type this: >-> (setq *q* 5) >5 Again, *q* is not special (global). After doing this, *q* just happens to have a value in the top-level environment, but it is not SPECIAL. > Then I evaluate the above DEFUN again. Then the following dialogue: Again, the closure over *q* is a lexical closure >-> (setq bq (new-queue 5)) > Finally, I type this: Now you're finally getting down to the interesting stuff. The following statement finally really makes *q* a SPECIAL, or global variable. *ALL* references to *q* will be special from now on. >-> (defvar *q* 6) >*Q* > I re-evaluate the DEFUN, and then this disgusting thing happens: It may be disgusting, but it's exactly right, and exactly what you TOLD it to do... >-> (setq cq (new-queue 5)) >#S(QUEUE :GET # :PUT # ) >-> (put-q cq 9) >Error: The second argument (ARRAY) to SYS:%LEXPR-ASET, 6, was of the wrong type. > The function expected an array. Because the reference to *q* in the :put closure is now a *dynamic* reference, not a *lexical* one. And what is the dynamic value of *q*? Exactly what you told it to be ... 6! > Note that 'aq and 'bq still work fine after this. Somehow the global value, >6, was used in the closure instead of the local definition of the array in the >LET. The same thing happens if I DEFVAR either of the other starred variables >in the function. Of course the sames thing happens, for exactly the sames (correct) reasons. > Conclusion: use SETQ instead of DEFVAR to make global variables. Conclusion: use DEFVAR to make global variables, since SETQ has no such power to do anything like that. Get a better grip on what's going on. Your application has no need of global variables in the first place, but that's another matter.... > WHAT is going on? > CAN this be written to be independent of the evaluation environment? >Bill || ...!purdue!bouma Rob Vollum Sun Microsystems Lexington, MA ...sun!sunne!robv, or rvollum@sun.com