From: �x���u
Subject: what's difference among variable definitions
Date: 
Message-ID: <MPG.ff2000ea12509a4989684@news.ntu.edu.tw>
lisp has
defvar
defparameter
defconstant
(I just know that variable created from defconstant can't be changed)

Dick Guan

From: Kent M Pitman
Subject: Re: what's difference among variable definitions
Date: 
Message-ID: <sfwogvsnvse.fsf@world.std.com>
········@csie.ntu.edu.tw (�x���u) writes:

> lisp has
> defvar
> defparameter

The above two differ functionally in that the latter does a 
 (SETQ var init)
and the former does 
 (UNLESS (BOUNDP 'var) (SETQ var init))

This leads to different patterns of use.

A typical use of
DEFVAR is where loading or re-loading the file does not want
to clobber the existing value. The two most common cases are
(a) a user option variable that the user might have set prior to
loading the file or (b) an "accmulation variable" for values
that are assigned across multiple files such that reloading a
single file ought not throw away all that info.  This second
usually looks like:
 (defvar *frobs* '())
 (defmacro def-frob (...)
   `(progn ...
           (push ... *frobs*)
           ...))
and then has def-frob forms in many files.

A typical pattern of use of DEFPARAMETER, and the reason it
gets its name, is usually a control parameter that a user
would not want to set in an init file. This is more like an
extra input to a function that happens to be global. e.g.,

(DEFPARAMETER *LAST-FROB-SEEN* NIL)
(DEFUN MAP-OVER-FROBS (FN)
  (MAPC #'(LAMBDA (X) (SETQ *LAST-FROB-SEEN* X)
		      (FUNCALL FN X))
        *FROBS*))

although as the above illustrates (if you think about it),
the use of DEFPARAMETER is often a judgment call since sometimes
if you were to re-load the file you'd still not want to clobber
the old value of *LAST-FROB-SEEN*.

On the other hand, though DEFVAR is often better, DEFVAR has
one major weakness that hits people a lot in debugging and
makes them switch to DEFPARAMETER: sometimes you'll write a
program like

 (DEFVAR *ITERATE-TIMES* 3)
 (DEFUN FOO () .... (DOTIMES (I *ITERATE-TIMES*) ..))

and get it debugged and then up it to 
 (DEFVAR *ITERATE-TIMES* 100)
in the source and re-load it and it won't work. This is
because it was already bound and didn't get reset.  
DEFPARAMTER will assure that it gets reset, but at the cost
that you can't set it in an init-file before loading this package,
and that even if you set it in some init file AFTER loading the
package, any subsequent re-loadings of the file containing the
algorithm will clobber your preference.

It's kind of a "clash of absolutes" problem--both the code author and
the user have a vital interest in the value being right.  It's
somewhat arbitraryin some cases but necessary to define in all cases
who will win.

> defconstant
> (I just know that variable created from defconstant can't be changed)

Yeah, this is just to allow you to symbolically name a quoted
constant.   Sometimes this is just purely aesthetic--sometimes it
also keeps you from accidentally getting a constant that is used
more than once from having different/inconsistent values in the 
same place.  Semantically, there is no difference between DEFCONSTANT
and DEFPARAMETER, except that the compiler is permitted (and intended)
to reason aggressively about the value.  In a sense, you can think
of this as an INLINE declaration for a variable.  
From: Kent M Pitman
Subject: Re: what's difference among variable definitions
Date: 
Message-ID: <sfwvhpzx582.fsf@world.std.com>
While half-asleep, I wrote:

> > defconstant
> > (I just know that variable created from defconstant can't be changed)
> 
> Yeah, this is just to allow you to symbolically name a quoted 
> constant. [...]

Actually, not just a quoted constant.  Also a computed constant.
e.g., I have been known to do things like:

 (defconstant +roman-numeral-weights+
    (let ((a (make-array 256 :initial-element nil)))
      (dolist (entry '((#\i 1) (#\v 5) (#\x 10) (#\l 50)
		       (#\c 100) (#\d 500) (#\m 1000)))
        (destructuring-bind (lc-letter val) entry
	  (let ((uc-letter (char-upcase lc-letter)))
	    (setf (aref a (char-code lc-letter)) val)
	    (setf (aref a (char-code uc-letter)) val))))
      a))
 (declaim (inline roman-numeral-weight))
 (defun roman-numeral-weight (c)
   ;; Assumes c is a character with code in range 0-255
   (svref (the simple-vector +roman-numeral-weights+)
	  (the (integer 0 255) (char-code (the character c)))))

where otherwise I'd have to have specified the weights as
 #(nil nil nil nil ...)
which I find to be error-prone, visually disruptive, and
lacking in perspicuity.

Also, an old quote I wanted to insert mostly for humor value here:

  "The primary purpose of the DATA statement is to give names to
   constants; instead of referring to pi as 3.141592653589793
   at every appearance, the variable PI can be given that value 
   with a DATA statement and used instead of the longer form as 
   a constant.  This also simplifies modifying the program 
   should the value of pi change."
      -- FORTRAN manual for Xerox Computers
From: David Bakhash
Subject: Re: what's difference among variable definitions
Date: 
Message-ID: <cxj1zsnhlty.fsf@hawk.bu.edu>
this is an excellent overview of the difference, and I have always
been a bit unsure and unclear on this point.  Thanks a lot, Kent.

dave