views:

139

answers:

4

I see that the Practical Common Lisp uses (defvar *db* nil) for setting up global variable. Isn't it OK to use setq for the same purposes?

What's the advantages/disadvantages of using defvar vs setq?

+4  A: 

DEFVAR establishes a new variable. SETQ assigns to a variable.

Most Lisp implementations I've used will issue a warning if you SETQ to a variable that doesn't yet exist.

Ken
+5  A: 

defvar and defparameter both introduce global variables. As Ken notes, setq assigns to a variable.

In addition, defvar will not clobber something previously defvar-ed. Seibel says later in the book (Chapter 6): "Practically speaking, you should use DEFVAR to define variables that will contain data you'd want to keep even if you made a change to the source code that uses the variable."

http://www.gigamonkeys.com/book/variables.html

For instance, if you have a global *db* for the database in the Simple Database chapter:

(defvar *db* nil)

...and you start playing with it at the REPL - adding, deleting things, etc - but then you make a change to the source file which contains that defvar form, reloading that file will not wipe out *db* and all the changes you might have made... I believe that setq will, as will defparameter. A more experienced Lisper please correct me if I'm wrong though.

spacemanaki
+2  A: 

defvar introduces a dynamic variable while setq is used to assign a value to a dynamic or lexical variable. The value of a dynamic variable is looked up in the environment that calls the function, while the value of a lexical variable is looked up in the environment where the function was defined. The following example will make the difference clear:

;; dynamic variable sample
> (defvar *x* 100)
*X*
> (defun fx () *x*)
FX
> (fx)
100
> (let ((*x* 500)) (fx)) ;; gets the value of *x* from the dynamic scope.
500
> (fx) ;; *x* now refers to the global binding.
100

;; example of using a lexical variable
> (let ((y 200))
   (let ((fy (lambda () (format t "~a~%" y))))
     (funcall fy) ;; => 200
     (let ((y 500))
       (funcall fy) ;; => 200, the value of lexically bound y
       (setq y 500) ;; => y in the current environment is modified
       (funcall fy)) ;; => 200, the value of lexically bound y, which was 
                     ;; unaffected by setq
     (setq y 500) => ;; value of the original y is modified.
     (funcall fy))) ;; => 500, the new value of y in fy's defining environment.

Dynamic variables are useful for passing around a default value. For instance, we can bind the dynamic variable *out* to the standard output, so that it becomes the default output of all io functions. To override this behavior, we just introduce a local binding:

> (defun my-print (s)
        (format *out* "~a~%" s))
MY-PRINT
> (my-print "hello")
hello
> (let ((*out* some-stream))
    (my-print " cruel ")) ;; goes to some-stream
> (my-print " world.")
world

A common use of lexical variables is in defining closures, to emulate objects with state. In the first example, the variable y in the binding environment of fy effectively became the private state of that function.

defvar will assign a value to a variable only if it is not already assigned. So the following re-definition of *x* will not change the original binding:

> (defvar *x* 400)
*X*
> *x*
100

We can assign a new value to *x* by using setq:

> (setq *x* 400)
400
> *x*
400
> (fx)
400
> (let ((*x* 500)) (fx)) ;; setq changed the binding of *x*, but 
                         ;; its dynamic property still remains.
500
> (fx)
400
Vijay Mathew
Unfortunately this is wrong. The exact effect of a (setq y 200) on a not declared/defined variable is undefined. Common Lisp also does not have global lexical variables. SETQ sets a variable. Nothing more. Either a dynamic variable or a lexical variable, depending on the variable provided. LET binds. SETQ sets.
Rainer Joswig
Also one can't define a function CL:PRINT, since that name is already taken by the standard function. FORMAT prints to streams, not files.
Rainer Joswig
@Rainer Thanks for pointing out the inaccuracies. I have updated the answer.
Vijay Mathew
+4  A: 

There are several ways to introduce variables.

DEFVAR and DEFPARAMETER introduce global dynamic variables. DEFVAR optionally sets it to some value, unless it is already defined. DEFPARAMETER sets it always to the provided value. SETQ does not introduce a variable.

(defparameter *number-of-processes* 10)

(defvar *world* (make-world))     ; the world is made only once.

Local variables are introduced with DEFUN, LAMBDA, LET, MULTIPLE-VALUE-BIND and others.

(defun foo (i-am-a-local-variable)
   (print i-am-a-local-variable))

(let ((i-am-also-a-local-variable 'hehe))
  (print i-am-also-a-local-variable))

Now, by default the local variables in above two forms a lexical, unless they are declared SPECIAL. Then they would be dynamic variables.

Next, there are also several forms to set a variable to new values. SET, SETQ, SETF and others. SETQ and SETF can set both lexical and special (dynamic) variables.

It is required for portable code that one sets variables that are already declared. The exact effect of setting a not declared variable is undefined by the standard.

So, if you know what your Common Lisp implementation does, you can use

(setq world (make-new-world))

in the Read-Eval-Print-Loop at the toplevel. But don't use it in your code, since the effect is not portable. Typically SETQ will set the variable. But some implementation might also declare the variable SPECIAL when it doesn't know it (CMUCL does that by default). That's almost always not what one would want. Use it for casual use if you know what you do, but not for code.

Same here:

(defun make-shiny-new-world ()
  (setq world (make-world 'shiny)))

First, such variables should be written as *world*, to make clear that it is a global special variable. Second, it should have been declared with DEFVAR or DEFPARAMETER before.

A typical Lisp compiler will complain that above variable is undeclared. Since global lexical variables don't exist in Common Lisp, the compiler has to generate code for a dynamic lookup. Some compiler then say, okay, we assume that this is a dynamic lookup, let's declare it to be special - since that is what we assume anyway.

Rainer Joswig