Path: utzoo!attcan!uunet!lll-winken!lll-lcc!ames!umd5!purdue!bouma
From: bouma@cs.purdue.EDU (William J. Bouma)
Newsgroups: comp.lang.lisp
Subject: SETQ vs DEFVAR at the top level
Summary: dynamic binding rears its ugly head again?
Keywords: closure, HELP
Message-ID: <4431@medusa.cs.purdue.edu>
Date: 30 Jun 88 20:52:07 GMT
Organization: Department of Computer Science, Purdue University
Lines: 103


     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
           #
         :PUT
           #
           )
-> (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
           #
         :PUT
           #
           )
-> (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
           #
         :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.

----------------------------------------------------------------------------   
     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   ||  ...!purdue!bouma