Common Lisp the Language, 2nd Edition

Next: The Print Name Up: Symbols Previous: Symbols

# 10.1. The Property List

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.

Compatibility note: In older Lisp implementations, the print name, value, and function definition of a symbol were kept on its property list. The value cell was introduced into MacLisp and Interlisp to speed up access to variables; similarly for the print-name cell and function cell (MacLisp does not use a function cell). Recent Lisp implementations such as Spice Lisp, Lisp Machine Lisp, and NIL have introduced all of these cells plus the package cell. None of the MacLisp system property names (`expr`, `fexpr`, `macro`, `array`, `subr`, `lsubr`, `fsubr`, and in former times `value` and `pname`) exist 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

Compatibility note: In MacLisp, the first argument to `get` could be a list, in which case the cdr of the list was treated as a so-called ``disembodied property list.'' The first argument to `get` could also be any other object, in which case `get` would always return `nil`. In Common Lisp, it is an error to give anything but a symbol as the first argument to `get`.

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.

Compatibility note: In MacLisp, this function is called `plist`; in Interlisp, it is called `getproplist`.

[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).

Compatibility note: The Interlisp function `listget` is similar to `getf`. The Interlisp function `listput` is similar to using `getf` with `setf`.

[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.

Next: The Print Name Up: Symbols Previous: Symbols