The Common Lisp structure mechanism provides a general way
to define data types similar to C's struct
types. A
structure is a Lisp object containing some number of slots,
each of which can hold any Lisp data object. Functions are
provided for accessing and setting the slots, creating or copying
structure objects, and recognizing objects of a particular structure
type.
In true Common Lisp, each structure type is a new type distinct from all existing Lisp types. Since the underlying Emacs Lisp system provides no way to create new distinct types, this package implements structures as vectors (or lists upon request) with a special ``tag'' symbol to identify them.
defstruct
form defines a new structure type called
name, with the specified slots. (The slots
may begin with a string which documents the structure type.)
In the simplest case, name and each of the slots
are symbols. For example,
(defstruct person name age sex)
defines a struct type called person
which contains three
slots. Given a person
object p, you can access those
slots by calling (person-name p)
, (person-age p)
,
and (person-sex p)
. You can also change these slots by
using setf
on any of these place forms:
(incf (person-age birthday-boy))
You can create a new person
by calling make-person
,
which takes keyword arguments :name
, :age
, and
:sex
to specify the initial values of these slots in the
new object. (Omitting any of these arguments leaves the corresponding
slot ``undefined,'' according to the Common Lisp standard; in Emacs
Lisp, such uninitialized slots are filled with nil
.)
Given a person
, (copy-person p)
makes a new
object of the same type whose slots are eq
to those of p.
Given any Lisp object x, (person-p x)
returns
true if x looks like a person
, false otherwise. (Again,
in Common Lisp this predicate would be exact; in Emacs Lisp the
best it can do is verify that x is a vector of the correct
length which starts with the correct tag symbol.)
Accessors like person-name
normally check their arguments
(effectively using person-p
) and signal an error if the
argument is the wrong type. This check is affected by
(optimize (safety ...))
declarations. Safety level 1,
the default, uses a somewhat optimized check that will detect all
incorrect arguments, but may use an uninformative error message
(e.g., ``expected a vector'' instead of ``expected a person
'').
Safety level 0 omits all checks except as provided by the underlying
aref
call; safety levels 2 and 3 do rigorous checking that will
always print a descriptive error message for incorrect inputs.
See Declarations.
(setq dave (make-person :name "Dave" :sex 'male)) => [cl-struct-person "Dave" nil male] (setq other (copy-person dave)) => [cl-struct-person "Dave" nil male] (eq dave other) => nil (eq (person-name dave) (person-name other)) => t (person-p dave) => t (person-p [1 2 3 4]) => nil (person-p "Bogus") => nil (person-p '[cl-struct-person counterfeit person object]) => t
In general, name is either a name symbol or a list of a name
symbol followed by any number of struct options; each slot
is either a slot symbol or a list of the form `(slot-name default-value slot-options...)
'. The default-value
is a Lisp form which is evaluated any time an instance of the
structure type is created without specifying that slot's value.
Common Lisp defines several slot options, but the only one
implemented in this package is :read-only
. A non-nil
value for this option means the slot should not be setf
-able;
the slot's value is determined when the object is created and does
not change afterward.
(defstruct person (name nil :read-only t) age (sex 'unknown))
Any slot options other than :read-only
are ignored.
For obscure historical reasons, structure options take a different form than slot options. A structure option is either a keyword symbol, or a list beginning with a keyword symbol possibly followed by arguments. (By contrast, slot options are key-value pairs not enclosed in lists.)
(defstruct (person (:constructor create-person) (:type list) :named) name age sex)
The following structure options are recognized.
:conc-name
|
The argument is a symbol whose print name is used as the prefix for
the names of slot accessor functions. The default is the name of
the struct type followed by a hyphen. The option |
:constructor
|
In the simple case, this option takes one argument which is an
alternate name to use for the constructor function. The default
is
In the full form of this option, the constructor name is followed
by an arbitrary argument list. See Program Structure, for a
description of the format of Common Lisp argument lists. All
options, such as
You can specify any number of full-format
The first constructor here takes its arguments positionally rather
than by keyword. (In official Common Lisp terminology, constructors
that work By Order of Arguments instead of by keyword are called
``BOA constructors.'' No, I'm not making this up.) For example,
The second constructor takes two keyword arguments, |
:copier
|
The argument is an alternate name for the copier function for
this type. The default is |
:predicate
|
The argument is an alternate name for the predicate which recognizes
objects of this type. The default is
In true Common Lisp, |
:include
|
This option implements a very limited form of C++-style inheritance.
The argument is the name of another structure type previously
created with
If there are extra arguments to the
Thus, if |
:print-function
|
In full Common Lisp, this option allows you to specify a function
which is called to print an instance of the structure type. The
Emacs Lisp system offers no hooks into the Lisp printer which would
allow for such a feature, so this package simply ignores
|
:type
|
The argument should be one of the symbols The vector representation for structure objects has the advantage that all structure slots can be accessed quickly, although creating vectors is a bit slower in Emacs Lisp. Lists are easier to create, but take a relatively long time accessing the later slots. |
:named
|
This option, which takes no arguments, causes a characteristic ``tag''
symbol to be stored at the front of the structure object. Using
The default, if you don't specify
Since unnamed structures don't have tags, |
:initial-offset
|
The argument must be a nonnegative integer. It specifies a
number of slots to be left ``empty'' at the front of the
structure. If the structure is named, the tag appears at the
specified position in the list or vector; otherwise, the first
slot appears at that position. Earlier positions are filled
with |
Except as noted, the defstruct
facility of this package is
entirely compatible with that of Common Lisp.