Path: utzoo!utgpu!water!watmath!clyde!att!osu-cis!killer!ames!lll-tis!lll-winken!uunet!mcvax!ukc!etive!aiva!jeff From: jeff@aiva.ed.ac.uk (Jeff Dalton) Newsgroups: comp.lang.lisp Subject: Re: SETQ vs DEFVAR at the top level Message-ID: <495@aiva.ed.ac.uk> Date: 8 Jul 88 20:16:44 GMT References: <4431@medusa.cs.purdue.edu> <4434@medusa.cs.purdue.edu> Reply-To: jeff@uk.ac.ed.aiva (Jeff Dalton) Organization: Dept. of AI, Univ. of Edinburgh, UK Lines: 105 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