User Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

cl:macros:defparameter [2019/07/14 17:00]
cl:macros:defparameter [2019/07/17 15:00] (current)
Line 1: Line 1:
 +====== Macro DEFPARAMETER,​ DEFVAR ======
 +
 +====Syntax====
 +  * **defparameter** //name initial-value [documentation] // → //​name// ​
 +  * **defvar ** //name //​[initial-value [documentation]]////​ → //name//
 +
 +====Arguments and Values====
 +  * //name// - a //​[[CL:​Glossary:​symbol]]//;​ not evaluated.
 +  * //​initial-value//​ - a //​[[CL:​Glossary:​form]]//;​ for **defparameter**,​ it is always //​[[CL:​Glossary:​evaluate|evaluated]]//,​ but for **defvar** it is //​[[CL:​Glossary:​evaluate|evaluated]]//​ only if //name// is not already //​[[CL:​Glossary:​bound]]//​.
 +  * //​documentation//​ - a //string//; not evaluated.
 +
 +====Description====
 +**defparameter** and **defvar** //​[[CL:​Glossary:​establish]]//​ //name// as a //​[[CL:​Glossary:​dynamic variable]]//​.
 +
 +**defparameter** unconditionally //​[[CL:​Glossary:​assign|assigns]]//​ the //​initial-value//​ to the //​[[CL:​Glossary:​dynamic variable]]//​ named //name//. **defvar**, by contrast, //​[[CL:​Glossary:​assign|assigns]]//​ //​initial-value//​ (if supplied) to the //​[[CL:​Glossary:​dynamic variable]]//​ named //name// only if //name// is not already //​[[CL:​Glossary:​bound]]//​.
 +
 +If no //​initial-value//​ is supplied, **defvar** leaves the //​[[CL:​Glossary:​value cell]]// of the //​[[CL:​Glossary:​dynamic variable]]//​ named //name// undisturbed;​ if //name// was previously //​[[CL:​Glossary:​bound]]//,​ its old //​[[CL:​Glossary:​value]]//​ persists, and if it was previously //​[[CL:​Glossary:​unbound]]//,​ it remains //​[[CL:​Glossary:​unbound]]//​.
 +
 +If //​documentation//​ is supplied, it is attached to //name// as a //​[[CL:​Glossary:​documentation string]]// of kind [[CL:​Types:​variable]].
 +
 +**defparameter** and **defvar** normally appear as a //​[[CL:​Glossary:​top level form]]//, but it is meaningful for them to appear as //​[[CL:​Glossary:​non-top-level form|non-top-level forms]]//. However, the compile-time side effects described below only take place when they appear as //​[[CL:​Glossary:​top level forms]]//.
 +
 +====Examples====
 +<​blockquote>​
 +(defparameter *p* 1) <​r>​*P*</​r>​
 +*p* <​r>​1</​r>​
 +(constantp '*p*) <​r>//​[[CL:​Glossary:​false]]//</​r>​
 +([[CL:​Macros:​defparameter]] *p* 2) <​r>​2</​r>​
 +(defparameter *p* 3) <​r>​*P*</​r>​
 +*p* <​r>​3</​r>​
 +
 +(defvar *v* 1) <​r>​*V*</​r>​
 +*v* <​r>​1</​r>​
 +(constantp '*v*) <​r>//​[[CL:​Glossary:​false]]//</​r>​
 +([[CL:​Macros:​defparameter]] *v* 2) <​r>​2</​r>​
 +(defvar *v* 3) <​r>​*V*</​r>​
 +*v* <​r>​2</​r>​
 +
 +(defun foo () 
 +  (let ((*p* 'p) (*v* 'v))
 +    (bar))) <​r>​FOO</​r>​
 +
 +(defun bar ()
 +  (list *p* *v*)) <​r>​BAR</​r>​
 +(foo) <r>(P V)</​r>​
 +</​blockquote>​
 +
 +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:
 +
 +<​blockquote>​
 +(defvar *the-interesting-numbers* '()) <​r>​*THE-INTERESTING-NUMBERS*</​r>​
 +(defmacro define-interesting-number (name n)
 +  `(progn (defvar ,name ,n)
 +     ​(pushnew ,name *the-interesting-numbers*) ',​name)) <​r>​DEFINE-INTERESTING-NUMBER</​r>​
 +(define-interesting-number *my-height* 168) ; cm <​r>​(168)</​r>​
 +(define-interesting-number *my-weight* 13) ; stones <​r>​(13 168)</​r>​
 +</​blockquote>​
 +
 +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:
 +
 +<​blockquote>​
 +(defparameter *default-beep-count* 3)
 +(defun beep (&​optional (n *default-beep-count*))
 +  (dotimes (i n) (si:%beep 1000. 100000.) (sleep 0.1)))
 +</​blockquote>​
 +
 +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** //​[[CL:​Glossary:​form]]//​ appears as a //​[[CL:​Glossary:​top level form]]//, the //​[[CL:​Glossary:​compiler]]//​ must recognize that the //name// has been proclaimed **[[CL:​Declarations:​special]]**. However, it must neither //​[[CL:​Glossary:​evaluate]]//​ the //​initial-value//​ //​[[CL:​Glossary:​form]]//​ nor //​[[CL:​Glossary:​assign]]//​ the //​[[CL:​Glossary:​dynamic variable]]//​ named //name// at compile time.
 +
 +There may be additional (//​[[CL:​Glossary:​implementation-defined]]//​) compile-time or run-time side effects, as long as such effects do not interfere with the correct operation of //​[[CL:​Glossary:​conforming program|conforming programs]]//​.
 +
 +====Affected By====
 +**defvar** is affected by whether //name// is already //​[[CL:​Glossary:​bound]]//​.
 +
 +====Exceptional Situations====
 +None.
 +
 +====See Also====
 +  * **[[CL:​Macros:​declaim|Macro DECLAIM]]**
 +  * **[[CL:​Macros:​defconstant|Macro DEFCONSTANT]]**
 +  * **[[CL:​Functions:​documentation|Generic Function DOCUMENTATION]]**
 +  * {\secref\Compilation}
 +
 +====Notes====
 +It is customary to name //​[[CL:​Glossary:​dynamic variables]]//​ with an //​[[CL:​Glossary:​asterisk]]//​ at the beginning and end of the name. e.g., ''​*foo*''​ is a good name for a //​[[CL:​Glossary:​dynamic variable]]//,​ but not for a //​[[CL:​Glossary:​lexical variable]]//;​ ''​foo''​ is a good name for a //​[[CL:​Glossary:​lexical variable]]//,​ but not for a //​[[CL:​Glossary:​dynamic variable]]//​. This naming convention is observed for all //​[[CL:​Glossary:​defined names]]// in Common Lisp; however, neither //​[[CL:​Glossary:​conforming program|conforming programs]]//​ nor //​[[CL:​Glossary:​conforming implementation|conforming implementations]]//​ are obliged to adhere to this convention.
 +
 +The intent of the permission for additional side effects is to allow //​[[CL:​Glossary:​implementation|implementations]]//​ to do normal "​bookkeeping"​ that accompanies definitions. For example, the //​[[CL:​Glossary:​macro expansion]]//​ of a **defvar** or **defparameter** //​[[CL:​Glossary:​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:
 +
 +<​blockquote>​
 +(defmacro defparameter (name initial-value &​optional (documentation nil documentation-p))
 +  `(progn ​
 +     ​(declaim (special ,​name)) ​
 +     ​([[CL:​Macros:​setf]] (symbol-value ',​name) ,​initial-value)
 +     ,​(when documentation-p ​
 +        `([[CL:​Macros:​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) ​
 +            ([[CL:​Macros:​setf]] (symbol-value ',​name) ,​initial-value))) ​
 +      ,(when documentation-p ​
 +         ​`([[CL:​Macros:​setf]] (documentation ',name '​variable) ',​documentation)) ',​name))
 +</​blockquote>​
 +
 +\issue{COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS:​CLARIFY} \issue{DEFVAR-INIT-TIME:​NOT-DELAYED} \issue{DEFVAR-DOCUMENTATION:​UNEVALUATED} \issue{DEFVAR-INITIALIZATION:​CONSERVATIVE} \issue{DEFINING-MACROS-NON-TOP-LEVEL:​ALLOW}