The preceding description of defstruct is all that the average user will need (or want) to know in order to use structures. The remainder of this chapter discusses more complex features of the defstruct facility.
This section explains each of the options that can be given to defstruct. A defstruct option may be either a keyword or a list of a keyword and arguments for that keyword. (Note that the syntax for defstruct options differs from the pair syntax used for slot-options. No part of any of these options is evaluated.)
The argument to the :conc-name option specifies an alternative prefix to be used. (If a hyphen is to be used as a separator, it must be specified as part of the prefix.) If nil is specified as an argument, then no prefix is used; then the names of the access functions are the same as the slot-names, and it is up to the user to name the slots reasonably.
Note that no matter what is specified for :conc-name, with a constructor function one uses slot keywords that match the slot-names, with no prefix attached. On the other hand, one uses the access-function name when using setf. Here is an example:
This option actually has a more general syntax that is explained in section 19.6.
The automatically defined copier function simply makes a new structure and transfers all components verbatim from the argument into the newly created structure. No attempt is made to make copies of the components. Corresponding components of the old and new structures will therefore be eql.
Now suppose you want to make a new structure to represent an astronaut. Since astronauts are people too, you would like them also to have the attributes of name, age, and sex, and you would like Lisp functions that operate on person structures to operate just as well on astronaut structures. You can do this by defining astronaut with the :include option, as follows:
The :include option causes the structure being defined to have the same slots as the included structure. This is done in such a way that the access functions for the included structure will also work on the structure being defined. In this example, an astronaut will therefore have five slots: the three defined in person and the two defined in astronaut itself. The access functions defined by the person structure can be applied to instances of the astronaut structure, and they will work correctly. Moreover, astronaut will have its own access functions for components defined by the person structure. The following examples illustrate how you can use astronaut structures:
The difference between the access functions person-name and astro-name is that person-name may be correctly applied to any person, including an astronaut, while astro-name may be correctly applied only to an astronaut. (An implementation may or may not check for incorrect use of access functions.)
At most one :include option may be specified in a single defstruct form. The argument to the :include option is required and must be the name of some previously defined structure. If the structure being defined has no :type option, then the included structure must also have had no :type option specified for it. If the structure being defined has a :type option, then the included structure must have been declared with a :type option specifying the same representation type.
If no :type option is involved, then the structure name of the including structure definition becomes the name of a data type, of course, and therefore a valid type specifier recognizable by typep; moreover, it becomes a subtype of the included structure. In the above example, astronaut is a subtype of person; hence
is true, indicating that all operations on persons will also work on astronauts.
The following is an advanced feature of the :include option. Sometimes, when one structure includes another, the default values or slot-options for the slots that came from the included structure are not what you want. The new structure can specify default values or slot-options for the included slots different from those the included structure specifies, by giving the :include option as
Each slot-description-j must have a slot-name or slot-keyword that is the same as that of some slot in the included structure. If slot-description-j has no default-init, then in the new structure the slot will have no initial value. Otherwise its initial value form will be replaced by the default-init in slot-description-j. A normally writable slot may be made read-only. If a slot is read-only in the included structure, then it must also be so in the including structure. If a type is specified for a slot, it must be the same as, or a subtype of, the type specified in the included structure. If it is a strict subtype, the implementation may or may not choose to error-check assignments.
For example, if we had wanted to define astronaut so that the default age for an astronaut is 45, then we could have said:
X3J13 voted in June 1988 to require any structure type created by defstruct (or defclass) to be disjoint from any of the types cons, symbol, array, number, character, hash-table, readtable, package, pathname, stream, and random-state. A consequence of this requirement is that it is an error to specify any of these types, or any of their subtypes, to the defstruct :include option. (The first edition said nothing explicitly about this. Inasmuch as using such a type with the :include option was not defined to work, one might argue that such use was an error in Common Lisp as defined by the first edition.)
If the :print-function option is not specified and the :type option also not specified, then a default printing function is provided for the structure that will print out all its slots using #S syntax (see section 22.1.4).
X3J13 voted in January 1989 to specify that user-defined printing functions for the defstruct :print-function option may print objects to the supplied stream using write, print1, princ, format, or print-object and expect circularities to be detected and printed using #n# syntax (when *print-circle* is non-nil, of course). See *print-circle*.
X3J13 voted in January 1989 to clarify that if the :print-function option is not specified but the :include option is specified, then the print function is inherited from the included structure type. Thus, for example, an astronaut will be printed by the same printing function that is used for person.
X3J13 in the same vote extended the print-function option as follows: If the print-function option is specified but with no argument, then the standard default printing function (that uses #S syntax) will be used. This provides a means of overriding the inheritance rule. For example, if person and astronaut had been defined as
then an ordinary person would be printed as “<Joe Schmoe, age 27>” but an astronaut would be printed as, for example,
using the default #S syntax (yuk).
These changes make the behavior of defstruct with respect to the :include option a bit more like the behavior of classes in CLOS.
Specifying this option has the effect of forcing a specific representation and of forcing the components to be stored in the order specified in the defstruct form in corresponding successive elements of the specified representation. It also prevents the structure name from becoming a valid type specifier recognizable by typep (see section 19.7).
Normally this option is not specified, in which case the structure is represented in an implementation-dependent manner.