bouma@cs.purdue.EDU (William J. Bouma) (07/01/88)
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! ---------------------------------------------------- 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)) (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 #<LEXICAL-CLOSURE (LAMBDA NIL #) 63021611> :PUT #<LEXICAL-CLOSURE (LAMBDA # # # ...) 63021613> ) -> (put-q aq 1) 1 -> (put-q aq 8) 8 -> (get-q aq) 1 -> (get-q aq) 8 -> (get-q aq) NIL ----------------------------------------- I type this: -> (setq *q* 5) 5 -------------------------------------------------------------------- Then I evaluate the above DEFUN again. Then the following dialogue: -> (setq bq (new-queue 5)) #S(QUEUE :GET #<LEXICAL-CLOSURE (LAMBDA NIL #) 63034070> :PUT #<LEXICAL-CLOSURE (LAMBDA # # # ...) 63034072> ) -> (put-q bq 4) 4 -> (get-q bq) 4 -------------------------------------- Finally, I type this: -> (defvar *q* 6) *Q* --------------------------------------------------------------------- I re-evaluate the DEFUN, and then this disgusting thing happens: -> (setq cq (new-queue 5)) #S(QUEUE :GET #<LEXICAL-CLOSURE (LAMBDA NIL #) 63040142> :PUT #<LEXICAL-CLOSURE (LAMBDA # # # ...) 63040144> ) -> (put-q cq 9) Error: The second argument (ARRAY) to SYS:%LEXPR-ASET, 6, was of the wrong type. The function expected an array. ---------------------------------------------------------------------------- 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. Note that I tried this code on both a Symbolics and in KCL and got the same results. Conclusion: use SETQ instead of DEFVAR to make global variables. WHAT is going on? CAN this be written to be independent of the evaluation environment? THANK you for your time! -- Bill <bouma@medusa.cs.purdue.edu> || ...!purdue!bouma
robv@pitstop.UUCP (Rob Vollum) (07/01/88)
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 #<LEXICAL-CLOSURE ...> :PUT #<LEXICAL-CLOSURE ...> ) <some tests proving it works deleted> > 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)) <more stuff, showing that it still works deleted> > 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 #<LEXICAL-CLOSURE ...> :PUT #<LEXICAL-CLOSURE ...> ) >-> (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 <bouma@medusa.cs.purdue.edu> || ...!purdue!bouma Rob Vollum Sun Microsystems Lexington, MA ...sun!sunne!robv, or rvollum@sun.com
doug@zaphod.prime.com (07/01/88)
I think the difference between SETQ and DEFVAR in this instance is easy to explain. A SETQ at top level will refer to a global, hence dynamically scoped variable. A SETQ does not make any declarations about the referenced variable. A DEFVAR form is not equivalent to a SETQ. It differs in one unimportant and one very important way: 1) Unimportant, it only will give a value to an already unbound variable 2) Important, it does the equivalent to (PROCLAIM '(SPECIAL variable)) That second thing is what has screwed you up. The proclaimation is global. It overrides the normal behavior everywhere you use the symbol. So not only does your binding of *Q* in the let become dynamic but any use of *Q* as a parameter would become dynamic. Lest you think that I'm just rationalizing the following passage from CLtL relates to LET bindings (and therefore do DEFUN, LAMBDA, etc.): ... each binding will be a lexical binding unless there is a special declaration to the contrary... PROCLAIM has global extent and effects all such declarations. -------------------- Douglas Rand Internet: doug@zaphod.prime.com Usenet: primerd!zaphod!doug Phone: (508) - 879 - 2960 Mail: Prime Computer, 500 Old Conn Path, MS10C-17, Framingham, Ma 01701 -> The above opinions are mine alone and are not influenced by my employer, my cat or the clothes I wear.
bouma@cs.purdue.EDU (William J. Bouma) (07/01/88)
Since my post yesterday I have figured out the answer to parts my own questions. The answer lies in that LET does a Dynamic shadowing of variables. That is, (LET ((X -3))) will only make a new binding of X if X is not dynamic in the calling environment. Otherwise it just gives the old binding of X a new value for the body of the LET clause. for example: (defvar x 6) (defun mc () (let ((x 2)) #'(lambda () (print x)))) The x in (print x) is the same x as in the (defvar x 6), which is also the same x as in the let. It seems like a lot of code I see just uses DEFVAR to declare all global variables as though that is what it is there for. In fact, I ran into this problem because that is what I was doing without really thinking about it. I thought, and it sounds to me from reading this group that others think that one should always use DEFVAR to declare global variables. Just recently I have read "setq does not make a binding" and "it may be bad style to make globals with setq". This is one of the reasons I made this post. I now hold that it is safer to use SETQ to declare global variables because it can be hard to track down this type of error in your closures. Does someone have problems with using SETQ thus? Also, I still want to know if anyone has a way to force a new binding of a variable in front of making a closure. Is there a way to declare x to be non-special before the LET? Can anyone tell me why the CL designers chose to have LET behave in this manner? -- Bill <bouma@medusa.cs.purdue.edu> || ...!purdue!bouma
willc@tekchips.TEK.COM (Will Clinger) (07/02/88)
In article <4431@medusa.cs.purdue.edu> bouma@cs.purdue.EDU (William J. Bouma) writes: > > 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! [long example deleted] That's right, friends. DEFVAR implicitly PROCLAIMs its variable to be SPECIAL, while SETQ does not. A variable PROCLAIMed SPECIAL by DEFVAR cannot be used as a lexical variable, and thus cannot be captured by a closure. Common Lisp provides DEFVAR (and PROCLAIM) to make it easier to introduce mysterious scoping bugs such as the one in Bouma's example. Without DEFVAR and PROCLAIM, each binding instance of a special variable would have to be explicitly declared as special, eliminating the need to scan entire programs in order to determine that a variable that appears lexical is in fact so. Peace, Will
dyb@iuvax.cs.indiana.edu (07/02/88)
>That's right, friends. DEFVAR implicitly PROCLAIMs its variable to be >SPECIAL, while SETQ does not. A variable PROCLAIMed SPECIAL by DEFVAR >cannot be used as a lexical variable... Corollary: Want to screw up a friend's Common Lisp session? Type "(defvar x nil)" when your friend isn't watching. Or better yet, put the defvar into your friend's Lisp init file. Kent
eric@nova.laic.uucp (Eric A. Raymond) (07/03/88)
In article <4434@medusa.cs.purdue.edu>, bouma@cs.purdue.EDU (William J. Bouma) writes: > Can anyone tell me why the CL designers chose to have LET behave in > this manner? How about: (defmacro WITH-SPECIAL-PRINTING (&body body) `(let ((*print-length* 3) (*print-level* 2)) ,@body)) This modifies the behavior of any calls to the standard output functions within the body (via the two special vars). It is much cleaner than saving the old value of each variable, setting a new value, executing the code, and then restoring the old value. This is a very useful behavior which intuitively reflects a natural interpretation of global variables. Global means gloabal, doesn't it. It should not mean global with local constraints. Eric A. Raymond - ...ucbvax!sun!sunncal!leadsv!laic!eric
jeff@aiva.ed.ac.uk (Jeff Dalton) (07/09/88)
I have now seen several articles on this topic, all at least partially incorrect. Even robv@pitstop.UUCP (Rob Vollum)'s response to Willaim Bouma's original message was slightly misleading, for it seemed to say "global" and "special" were the same thing yet also that a variable might have a value in the top-level environment and not be special. Neither is quite correct. 1. In Common Lisp, it turns out that all global variables are special, but it is possible for a Lisp to have global variables that are lexically scoped (Scheme, for example). These happen not to exist in Common Lisp, but the possibility is enough to show the concepts are different. Consider an example. We can give a global variable A a value without explicitly making it special. (setq a 'global-a) A function can refer to that variable A. It seems reasonable to say that if the global variable A has lexical scope, the function will see GLOBAL-A as the value of A unless the value is changed by another SETQ. (defun fa () a) Here is the test: we can make an A that is explicitly special and call the function to see if it refers to the special variable or not. (let ((a 'special-a)) ;new special binding (declare (special a)) ;because of this declaration (fa)) ==> special-a This result shows that we can regard the global variable, given a value by setq, as being special (i.e., dynamically scoped). No DEFVAR is involved. But suppose the global A had lexical scope. Then the above example should be equivalent to: (let ((a 'global-a)) ;lexical variable A (labels ((fa () a)) ;refers to that lexical A (let ((a 'dynamic-a)) ;special variable A (declare (special a)) (fa)))) ==> global-a This shows that Lisp's behavior in the case where the global variable had lexical scope would be different. So, (all) global variables are special, though in a different Lisp some might not be. 2. My second point about Rob Vollum's article was that it was not quite correct to say a variable might have a value in the top-level environment and yet not be special. The reason I say this is again that all global variables in Common Lisp are special variables. However, in the absence of a special proclamation there may be other variables with the same name that are not special. The example was this: (defun new-queue (size) (let ((*q* (make-array size)) (*head* 0) (*tail* 0)) (make-queue ...))) (setq *q* 5) And Rob's comment: 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. The problem is that there are two different variables named *Q*. The SETQ changed the value of the special variable *Q*, but the *Q* in the LET in NEW-QUEUE is not special. We can even make a context in which we can refer to both kinds of variable at once: (defmacro dynamic-ref (var) `(locally (declare (special ,var)) ,var)) (let ((a 'special-a)) (declare (special a)) (let ((a 'lexical-a)) (list a (dynamic-ref a)))) ==> (lexical-a global-a) 3. It has also been claimed that SETQ never establishes a binding but DEFVAR does. Something very like this is true in several dialects of Scheme, but is misleading when applied to Common Lisp. In CL, a DEFVAR does a SETQ (if the variable does not already have a value). The main difference between DEFVAR and a top-level SETQ is that DEFVAR *also* proclaims the variable special. (A proclamation is a declaration established by PROCLAIM instead of DECLARE, and a special proclamation pervasively affects all bindings and references.) A SETQ alone does not declare or proclaim anything: it just assigns a value. Whether this counts as establishing a binding, in the case where the (global) variable did not already have a value, is largely a matter of how you want to describe things. But if SETQ does not establish a binding, neither does DEFVAR. Jeff Dalton, JANET: J.Dalton@uk.ac.ed AI Applications Institute, ARPA: J.Dalton%uk.ac.ed@nss.cs.ucl.ac.uk Edinburgh University. UUCP: ...!ukc!ed.ac.uk!J.Dalton
jeff@aiva.ed.ac.uk (Jeff Dalton) (07/11/88)
In article <4434@medusa.cs.purdue.edu> bouma@cs.purdue.EDU (William J. Bouma) writes: >The answer lies in that LET does a Dynamic shadowing of variables. >That is, (LET ((X -3))) will only make a new binding of X if X is not dynamic >in the calling environment. Otherwise it just gives the old binding of X a new >value for the body of the LET clause. > Also, I still want to know if anyone has a way to force a new binding >of a variable in front of making a closure. Is there a way to declare x to >be non-special before the LET? You might say that a LET always gives a new binding. If you read the description of LET in CLtL, you will see that it does not say lexical variables are given new bindings while special variables are not. All it says is "each binding will be a lexical binding unless there is a SPECIAL declaration to the contrary". But since there is only one value of a special variable accessible at a given time, the difference between having multiple bindings (but only one visible) and having one binding (whose value changes, with a way to change it back) may not seem that significant. That it is not significant, however, also means that it is not the source of your problem. What you want is a way to ensure a variable has lexical scope (so it can be closed over). Unfortunately, there is no way to do this in Common Lisp: special proclamations cannot be shadowed, overridden, or otherwise undone. >Can anyone tell me why the CL designers chose to have LET behave in >this manner? Since it's not just LET that behaves this way, it's really the semantics of special variables that you want explained. The relevant issues seem to be the following: (1) Why do special proclamations pervasively affect bindings -- i.e., why does LET not automatically shadow special proclamations as it does other special declarations? The answer is indicated on page 158 of CLtL: for convenience and compatibility with MacLisp. Special proclamations let you make a given identifier the name of a special variable everywhere. Otherwise, to make *x* special everywhere you would need a (declare (special *x*)) for every form that bound *x*. The use of DEFVAR to proclaim variables special goes well with the *name* convention, because it makes a special proclamation and hence makes *name* special everywhere. (2) Why is there no way to declare something lexical -- i.e., no way override special proclamations and so guarantee that a variable is lexical? In part this may have been an oversight or an attempt to make the language simpler (though asymmetric). Moreover, it is unnecessary if the *name* convention is actually followed. If *name* always means a special variable, you will never want to make such names nonspecial; and no other names will ever be special. (3) Why are special variables not included in closures? Some Lisps have supported closures over the dynamic environment, but generally with a high cost in efficiency or implementation complexity. ----- >It seems like a lot of code I see just uses DEFVAR to declare all global >variables as though that is what it is there for. In fact, I ran into this >problem because that is what I was doing without really thinking about it. >I thought, and it sounds to me from reading this group that others think that >one should always use DEFVAR to declare global variables. What CLtL says about DEFVAR and style is that DEFVAR is the recommended way to declare the use of a special variable (page 68) or the conventional way to make a special proclamation (page 158). It does not say DEFVAR is the correct way to declare global variables. Indeed, Common Lisp does not require the declaration of global variables at all. You might even say Common Lisp does not have global variables. What it has is special variables, which may have global values. In any case, the *name* convention implies that *name* should always be special (i.e., dynamically scoped). The way to ensure that is to proclaim such names special, and the recommended way to proclaim them special is to use DEFVAR. The problem with SETQ, then, is that it does not proclaim the variable special. If you merely (SETQ *X* 10) and then use *X* as a formal parameter or in a LET, you will have a *X* that is not special. So, if you use the *name* convention, you will want to use DEFVAR. Finally: you should use the *name* convention because it lets you determine whether a variable is special (modulo spelling errors and omitted DEFVARs) by local inspection. Using SETQ and the *name* convention, or abandoning the convention, might have some advantages, but overall (or so the argument goes) would be worse. In other words, there is a reason to use DEFVAR, but thinking of it in terms of declaring global variables is probably more confusing than enlightening. (But see below.) >Just recently I have read "setq does not make a binding" and "it may >be bad style to make globals with setq". In a sense, it is certainly true that SETQ does not make a binding (while LET does). When comparing with DEFVAR, however, the question is top-level bindings. If we consider a (special) variable without a value in the top-level environment, CLtL is somewhat confusing. On page 56, it says such a variable is unbound "unless and until explicitly assigned a value", implying that assignment (SETQ) will make it bound. But it also says the global value is the value "when there are currently no bindings". In some other dialects of Lisp, the situation is clearer. In T, for example, DEFINE and LSET establish top-level bindings, and SET does not: a SET when there is no binding is an error. But the difficulty in Common Lisp really concerns how we should talk about top-level values, not the difference between SETQ and DEFVAR. When DEFVAR gives a value to a variable, it does so by assignment; and assignment is what SETQ does. So whatever they do about bindings, DEFVAR and SETQ do the same thing. What DEFVAR does that SETQ does not, except for possible "system- dependent bookkeeping actions", is to proclaim the variable special. >I now hold that it is safer to use SETQ to declare global variables >because it can be hard to track down this type of error in your closures. But, for other reasons, your strategy may be worse overall. What makes DEFVAR acceptably safe is the *name* convention. >Does someone have problems with using SETQ thus? Yes. If you use SETQ instead of DEFVAR you will either have difficulty using the *name* convention consistently (you will have to remember to put in special declarations or adopt some macros that to so automatically) or you will have to abandon the convention and so have difficulty keeping track of which variables are special. The exception would be if you use special variables only as global variables and never give them a value except the top level one. (Perhaps this is all you have ever had in mind, and if so I apologize for the misunderstanding.) This is often done in other languages, but then they give you no choice. It is less often done in Lisp because one usually wants to give a special variable a value only temporarily. That is, one wants to take advantage dynamic scope and not just to use global variables. ----- A better explanation of these points can be obtained by adopting some consistent terminology that makes it clear just what is meant by "variable", "binding", and so on. For this, you might look at the Scheme report or Gabriel and Pitman's "Technical Issues of Separation in Function Cells and Value Cells" in the first issue of Lisp and Symbolic Computation. To follow the details of Common Lisp, you may have to read the following sections of CLtL: * Chapter 3: Scope and Extent * Chapter 5: Program Structure, sections 5.1.2 and 5.3.2 * Chapter 7: Control Structure, sections 7.1.1 and 7.1.2 * Chapter 9: Declarations Jeff Dalton, JANET: J.Dalton@uk.ac.ed AI Applications Institute, ARPA: J.Dalton%uk.ac.ed@nss.cs.ucl.ac.uk Edinburgh University. UUCP: ...!ukc!ed.ac.uk!J.Dalton
ng@pur-phy (Nicholas J. Giordano) (07/21/88)
I am sorry if this is not the right group for this question, but my site has no newsgroup on logo. Afterall, logo is related to lisp, so here goes. I have been fooling around with / learning logo, along with my kids. I have a couple of good books, but I can't find any books which give the "definition" of the language. What I have in mind is the sort of thing which K&R provide for C. So, can anyone provide a reference of this kind? Many thanks in advance. Nick