Common Lisp the Language, 2nd Edition
Since its inception, Lisp has associated with each symbol a kind of tabular data structure called a property list (plist for short). A property list contains zero or more entries; each entry associates with a key (called the indicator), which is typically a symbol, an arbitrary Lisp object (called the value or, sometimes, the property). There are no duplications among the indicators; a property list may only have one property at a time with a given name. In this way, given a symbol and an indicator (another symbol), an associated value can be retrieved.
A property list is very similar in purpose to an association list. The difference is that a property list is an object with a unique identity; the operations for adding and removing property-list entries are destructive operations that alter the property list rather than making a new one. Association lists, on the other hand, are normally augmented non-destructively (without side effects) by adding new entries to the front (see acons and pairlis).
A property list is implemented as a memory cell containing a list with an even number (possibly zero) of elements. (Usually this memory cell is the property-list cell of a symbol, but any memory cell acceptable to setf can be used if getf and remf are used.) Each pair of elements in the list constitutes an entry; the first item is the indicator, and the second is the value. Because property-list functions are given the symbol and not the list itself, modifications to the property list can be recorded by storing back into the property-list cell of the symbol.
When a symbol is created, its property list is initially empty. Properties are created by using get within a setf form.
Common Lisp does not use a symbol's property list as extensively as earlier Lisp implementations did. Less-used data, such as compiler, debugging, and documentation information, is kept on property lists in Common Lisp.
In Common Lisp, the notion of ``disembodied property list'' introduced in MacLisp is eliminated. It tended to be used for rather kludgy things, and in Lisp Machine Lisp is often associated with the use of locatives (to make it ``off by one'' for searching alternating keyword lists). In Common Lisp special setf-like property-list functions are introduced: getf and remf.
[Function]
get symbol indicator &optional default
get searches the property list of symbol for an indicator eq to indicator. The first argument must be a symbol. If one is found, then the corresponding value is returned; otherwise default is returned.
If default is not specified, then nil is used for default.
Note that there is no way to distinguish an absent property from one whose value is default.
(get x y) == (getf (symbol-plist x) y)
Suppose that the property list of foo is (bar t baz 3 hunoz "Huh?"). Then, for example:
(get 'foo 'baz) => 3 (get 'foo 'hunoz) => "Huh?" (get 'foo 'zoo) => nil
What Common Lisp calls get, Interlisp calls getprop.
What MacLisp and Interlisp call putprop is accomplished in Common Lisp by using get with setf.
setf may be used with get to create a new property-value pair, possibly replacing an old pair with the same property name. For example:
(get 'clyde 'species) => nil (setf (get 'clyde 'species) 'elephant) => elephant and now (get 'clyde 'species) => elephant
The default argument may be specified to get in this context; it is ignored by setf but may be useful in such macros as push that are related to setf:
(push item (get sym 'token-stack '(initial-item)))
means approximately the same as
(setf (get sym 'token-stack '(initial-item)) (cons item (get sym 'token-stack '(initial-item))))
which in turn would be treated as simply
(setf (get sym 'token-stack) (cons item (get sym 'token-stack '(initial-item))))
X3J13 voted in March 1989 (REMF-DESTRUCTION-UNSPECIFIED)
to clarify the permissible side effects of certain operations;
(setf (get symbol indicator) newvalue)
is required to behave exactly the same as
(setf (getf (symbol-plist symbol) indicator) newvalue).
[Function]
remprop symbol indicator
This removes from symbol the property with an indicator eq to indicator. The property indicator and the corresponding value are removed by destructively splicing the property list. It returns nil if no such property was found, or non-nil if a property was found.
(remprop x y) == (remf (symbol-plist x) y)
For example, if the property list of foo is initially
(color blue height 6.3 near-to bar)
then the call
(remprop 'foo 'height)
returns a non-nil value after altering foo's property list to be
(color blue near-to bar)
X3J13 voted in March 1989 (REMF-DESTRUCTION-UNSPECIFIED)
to clarify the permissible side effects of certain operations;
(remprop symbol indicator)
is required to behave exactly the same as
(remf (symbol-plist symbol) indicator).
[Function]
symbol-plist symbol
This returns the list that contains the property pairs of symbol; the contents of the property-list cell are extracted and returned.
Note that using get on the result of symbol-plist does not work. One must give the symbol itself to get or else use the function getf.
setf may be used with symbol-plist to destructively replace the entire property list of a symbol. This is a relatively dangerous operation, as it may destroy important information that the implementation may happen to store in property lists. Also, care must be taken that the new property list is in fact a list of even length.
[Function]
getf place indicator &optional default
getf searches the property list stored in place for an indicator eq to indicator. If one is found, then the corresponding value is returned; otherwise default is returned. If default is not specified, then nil is used for default. Note that there is no way to distinguish an absent property from one whose value is default. Often place is computed from a generalized variable acceptable to setf.
setf may be used with getf, in which case the place must indeed be acceptable as a place to setf. The effect is to add a new property-value pair, or update an existing pair, in the property list kept in the place. The default argument may be specified to getf in this context; it is ignored by setf but may be useful in such macros as push that are related to setf. See the description of get for an example of this.
X3J13 voted in March 1989 (REMF-DESTRUCTION-UNSPECIFIED)
to clarify the permissible side effects of certain operations;
setf used with getf is permitted to perform a setf
on the place or on any part, car or cdr, of the
top-level list structure held by that place.
X3J13 voted in March 1988 (PUSH-EVALUATION-ORDER)
to clarify order of evaluation (see section 7.2).
[Macro]
remf place indicator
This removes from the property list stored in place the property with an indicator eq to indicator. The property indicator and the corresponding value are removed by destructively splicing the property list. remf returns nil if no such property was found, or some non-nil value if a property was found. The form place may be any generalized variable acceptable to setf. See remprop.
X3J13 voted in March 1989 (REMF-DESTRUCTION-UNSPECIFIED)
to clarify the permissible side effects of certain operations;
remf is permitted to perform a setf
on the place or on any part, car or cdr, of the
top-level list structure held by that place.
X3J13 voted in March 1988 (PUSH-EVALUATION-ORDER)
to clarify order of evaluation (see section 7.2).
[Function]
get-properties place indicator-list
get-properties is like getf, except that the second argument is a list of indicators. get-properties searches the property list stored in place for any of the indicators in indicator-list until it finds the first property in the property list whose indicator is one of the elements of indicator-list. Normally place is computed from a generalized variable acceptable to setf.
get-properties returns three values. If any property was found, then the first two values are the indicator and value for the first property whose indicator was in indicator-list, and the third is that tail of the property list whose car was the indicator (and whose cadr is therefore the value). If no property was found, all three values are nil. Thus the third value serves as a flag indicating success or failure and also allows the search to be restarted, if desired, after the property was found.