CLHS: Macro DEFPARAMETER, DEFVAR

#

Macro DEFPARAMETER, DEFVAR

Syntax:

defparameter name initial-value [documentation] => name

defvar name [initial-value [documentation]] => name

Arguments and Values:

name---a symbol; not evaluated.

initial-value---a form; for defparameter, it is always evaluated, but for defvar it is evaluated only if name is not already bound.

documentation---a string; not evaluated.

Description:

defparameter and defvar establish name as a dynamic variable.

defparameter unconditionally assigns the initial-value to the dynamic variable named name. defvar, by contrast, assigns initial-value (if supplied) to the dynamic variable named name only if name is not already bound.

If no initial-value is supplied, defvar leaves the value cell of the dynamic variable named name undisturbed; if name was previously bound, its old value persists, and if it was previously unbound, it remains unbound.

If documentation is supplied, it is attached to name as a documentation string of kind variable.

defparameter and defvar normally appear as a top level form, but it is meaningful for them to appear as non-top-level forms. However, the compile-time side effects described below only take place when they appear as top level forms.

Examples:

     (defparameter *p* 1) =>  *P*
     *p* =>  1
     (constantp '*p*) =>  false
     (setq *p* 2) =>  2
     (defparameter *p* 3) =>  *P*
     *p* =>  3

     (defvar *v* 1) =>  *V*
     *v* =>  1
     (constantp '*v*) =>  false
     (setq *v* 2) =>  2
     (defvar *v* 3) =>  *V*
     *v* =>  2

     (defun foo ()
       (let ((*p* 'p) (*v* 'v))
         (bar))) =>  FOO
     (defun bar () (list *p* *v*)) =>  BAR
     (foo) =>  (P V)

The principal operational distinction between defparameter and defvar is that defparameter makes an unconditional assignment to name, while defvar makes a conditional one. In practice, this means that defparameter is useful in situations where loading or reloading the definition would want to pick up a new value of the variable, while defvar is used in situations where the old value would want to be retained if the file were loaded or reloaded. For example, one might create a file which contained:

     (defvar *the-interesting-numbers* '())
     (defmacro define-interesting-number (name n)
       `(progn (defvar ,name ,n)
               (pushnew ,name *the-interesting-numbers*)
               ',name))
     (define-interesting-number *my-height* 168) ;cm
     (define-interesting-number *my-weight* 13)  ;stones

Here the initial value, `()`, for the variable `*the-interesting-numbers*` is just a seed that we are never likely to want to reset to something else once something has been grown from it. As such, we have used defvar to avoid having the `*interesting-numbers*` information reset if the file is loaded a second time. It is true that the two calls to define-interesting-number here would be reprocessed, but if there were additional calls in another file, they would not be and that information would be lost. On the other hand, consider the following code:

     (defparameter *default-beep-count* 3)
     (defun beep (&optional (n *default-beep-count*))
       (dotimes (i n) (si:%beep 1000. 100000.) (sleep 0.1)))

Here we could easily imagine editing the code to change the initial value of `*default-beep-count*`, and then reloading the file to pick up the new value. In order to make value updating easy, we have used defparameter.

On the other hand, there is potential value to using defvar in this situation. For example, suppose that someone had predefined an alternate value for `*default-beep-count*`, or had loaded the file and then manually changed the value. In both cases, if we had used defvar instead of defparameter, those user preferences would not be overridden by (re)loading the file.

The choice of whether to use defparameter or defvar has visible consequences to programs, but is nevertheless often made for subjective reasons.

Side Effects:

If a defvar or defparameter form appears as a top level form, the compiler must recognize that the name has been proclaimed special. However, it must neither evaluate the initial-value form nor assign the dynamic variable named name at compile time.

There may be additional (implementation-defined) compile-time or run-time side effects, as long as such effects do not interfere with the correct operation of conforming programs.

Affected By:

defvar is affected by whether name is already bound.

Exceptional Situations: None.

See Also:

declaim, defconstant, documentation, Section 3.2 (Compilation)

Notes:

It is customary to name dynamic variables with an asterisk at the beginning and end of the name. e.g., `*foo*` is a good name for a dynamic variable, but not for a lexical variable; `foo` is a good name for a lexical variable, but not for a dynamic variable. This naming convention is observed for all defined names in Common Lisp; however, neither conforming programs nor conforming implementations are obliged to adhere to this convention.

The intent of the permission for additional side effects is to allow implementations to do normal ``bookkeeping'' that accompanies definitions. For example, the macro expansion of a defvar or defparameter form might include code that arranges to record the name of the source file in which the definition occurs.

defparameter and defvar might be defined as follows:

     (defmacro defparameter (name initial-value
                             &optional (documentation nil documentation-p))
       `(progn (declaim (special ,name))
               (setf (symbol-value ',name) ,initial-value)
               ,(when documentation-p
                  `(setf (documentation ',name 'variable) ',documentation))
               ',name))
     (defmacro defvar (name &optional
                            (initial-value nil initial-value-p)
                            (documentation nil documentation-p))
       `(progn (declaim (special ,name))
               ,(when initial-value-p
                  `(unless (boundp ',name)
                     (setf (symbol-value ',name) ,initial-value)))
               ,(when documentation-p
                  `(setf (documentation ',name 'variable) ',documentation))
               ',name))

The following X3J13 cleanup issues, not part of the specification, apply to this section:

- COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS:CLARIFY
- DEFINING-MACROS-NON-TOP-LEVEL:ALLOW
- DEFVAR-INITIALIZATION:CONSERVATIVE
- DEFVAR-DOCUMENTATION:UNEVALUATED
- DEFVAR-INIT-TIME:NOT-DELAYED

Copyright 1996-2005, LispWorks Ltd. All rights reserved.