123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170 |
- @node Structures, Conditions, Objects, Top
- @chapter Structures
- @menu
- * Structures Dictionary::
- @end menu
- @node Structures Dictionary, , Structures, Structures
- @section Structures Dictionary
- @c including dict-structures
- @menu
- * defstruct::
- * copy-structure::
- @end menu
- @node defstruct, copy-structure, Structures Dictionary, Structures Dictionary
- @subsection defstruct [Macro]
- @code{defstruct} @i{name-and-options @r{[}documentation@r{]} @{!@i{slot-description}@}{*}}@*
- @result{} @i{structure-name}
- @w{@i{name-and-options} ::=structure-name | @r{(}structure-name [[!@i{options}]]@r{)}}
- @w{@i{options} ::=!@i{conc-name-option} |}
- @w{ @{!@i{constructor-option}@}{*} |}
- @w{ !@i{copier-option} |}
- @w{ !@i{include-option} |}
- @w{ !@i{initial-offset-option} |}
- @w{ !@i{named-option} |}
- @w{ !@i{predicate-option} |}
- @w{ !@i{printer-option} |}
- @w{ !@i{type-option}}
- @w{@i{conc-name-option} ::=@t{:conc-name} | @r{(}@t{:conc-name}@r{)} | @r{(}@t{:conc-name} @i{conc-name}@r{)}}
- @w{@i{constructor-option} ::=@t{:constructor} |}
- @w{ @r{(}@t{:constructor}@r{)} |}
- @w{ @r{(}@t{:constructor} @i{constructor-name}@r{)} |}
- @w{ @r{(}@t{:constructor} @i{constructor-name} @i{constructor-arglist}@r{)}}
- @w{@i{copier-option} ::=@t{:copier} | @r{(}@t{:copier}@r{)} | @r{(}@t{:copier} @i{copier-name}@r{)}}
- @w{@i{predicate-option} ::=@t{:predicate} | @r{(}@t{:predicate}@r{)} | @r{(}@t{:predicate} @i{predicate-name}@r{)}}
- @w{@i{include-option} ::=@r{(}@t{:include} @i{included-structure-name} @{!@i{slot-description}@}{*}@r{)}}
- @w{@i{printer-option} ::=!@i{print-object-option} | !@i{print-function-option}}
- @w{@i{print-object-option} ::=@r{(}@t{:print-object} @i{printer-name}@r{)} | @r{(}@t{:print-object}@r{)}}
- @w{@i{print-function-option} ::=@r{(}@t{:print-function} @i{printer-name}@r{)} | @r{(}@t{:print-function}@r{)}}
- @w{@i{type-option} ::=@r{(}@t{:type} @i{type}@r{)}}
- @w{@i{named-option} ::=@t{:named}}
- @w{@i{initial-offset-option} ::=@r{(}@t{:initial-offset} @i{initial-offset}@r{)}}
- @w{@i{slot-description} ::=@i{slot-name} | }
- @w{ @r{(}@i{slot-name} @r{[}@i{slot-initform} [[!@i{slot-option}]]@r{]}@r{)}}
- @w{@i{slot-option} ::=@t{:type} @i{slot-type} | }
- @w{ @t{:read-only} @i{slot-read-only-p}}
- @subsubheading Arguments and Values::
- @i{conc-name}---a @i{string designator}.
- @i{constructor-arglist}---a @i{boa lambda list}.
- @i{constructor-name}---a @i{symbol}.
- @i{copier-name}---a @i{symbol}.
- @i{included-structure-name}---an already-defined @i{structure name}.
- Note that a @i{derived type} is not permissible,
- even if it would expand into a @i{structure name}.
- @i{initial-offset}---a non-negative @i{integer}.
- @i{predicate-name}---a @i{symbol}.
- @i{printer-name}---a @i{function name} or a @i{lambda expression}.
- @i{slot-name}---a @i{symbol}.
- @i{slot-initform}---a @i{form}.
- @i{slot-read-only-p}---a @i{generalized boolean}.
- @i{structure-name}---a @i{symbol}.
- @i{type}---one of the @i{type specifiers}
- @b{list},
- @b{vector},
- or @t{(vector @i{size})},
- or some other @i{type specifier} defined
- by the @i{implementation} to be appropriate.
- @i{documentation}---a @i{string}; not evaluated.
- @subsubheading Description::
- @b{defstruct} defines a structured @i{type}, named @i{structure-type},
- with named slots as specified by the @i{slot-options}.
- @b{defstruct} defines @i{readers} for the slots and
- arranges for @b{setf} to work properly on such
- @i{reader} functions.
- Also, unless overridden, it
- defines a predicate named @t{@i{name}-p},
- defines a constructor function named @t{make-@i{constructor-name}},
- and defines a copier function named @t{copy-@i{constructor-name}}.
- All names of automatically created functions might automatically
- be declared @b{inline} (at the discretion of the @i{implementation}).
- If @i{documentation} is supplied, it is attached to @i{structure-name}
- as a @i{documentation string} of kind @b{structure},
- and unless @t{:type} is used, the @i{documentation} is also attached
- to @i{structure-name} as a @i{documentation string} of kind
- @b{type} and as a @i{documentation string} to the @i{class} @i{object}
- for the @i{class} named @i{structure-name}.
- @b{defstruct} defines a constructor function that is used to
- create instances of the structure created by @b{defstruct}.
- The default name is @t{make-@i{structure-name}}.
- A different name can be supplied
- by giving the name as the argument to the @i{constructor} option.
- @b{nil} indicates that no constructor function will be created.
- After a new structure type has been defined, instances of that type
- normally can be created by using the constructor function for the
- type.
- A call to a constructor function is of the following form:
- @w{ (@t{constructor-function-name}}@*
- @w{ @t{slot-keyword-1 form-1}}@*
- @w{ @t{slot-keyword-2 form-2}}@*
- @w{ ...)}@*
- The arguments to the constructor function are all keyword arguments. Each
- slot keyword argument must be
- a keyword whose name corresponds to the name of a structure slot.
- All the @i{keywords} and @i{forms}
- are evaluated.
- If a slot is not initialized in this way,
- it is initialized by evaluating @i{slot-initform} in the slot description
- at the time the constructor function is called.
- If no @i{slot-initform} is supplied,
- the consequences are undefined if an attempt is later made to read the slot's value
- before a value is explicitly assigned.
- Each @i{slot-initform} supplied for a @b{defstruct} component,
- when used by the constructor function for an otherwise unsupplied
- component, is re-evaluated on every call to the
- constructor function.
- The @i{slot-initform} is not evaluated
- unless it is needed in the creation of a particular structure
- instance. If it is never needed, there can be no type-mismatch
- error, even if the @i{type}
- of the slot is specified; no warning
- should be issued in this case.
- For example, in the following sequence, only the last call is an error.
- @example
- (defstruct person (name 007 :type string))
- (make-person :name "James")
- (make-person)
- @end example
- It is as if the @i{slot-initforms} were
- used as @i{initialization forms} for the @i{keyword parameters}
- of the constructor function.
- The @i{symbols} which name the slots must not be used by the
- @i{implementation} as the @i{names} for the @i{lambda variables}
- in the constructor function, since one or more of those @i{symbols}
- might have been proclaimed @b{special} or might be defined as
- the name of a @i{constant variable}.
- The slot default init forms are evaluated
- in the @i{lexical environment} in which the @b{defstruct} form itself appears and
- in the @i{dynamic environment} in which the call to the constructor function appears.
- For example, if the form @t{(gensym)} were used as an initialization form,
- either in the constructor-function call or as the default initialization form
- in @b{defstruct}, then every call to the constructor function would call
- @b{gensym} once to generate a new @i{symbol}.
- Each @i{slot-description} in @b{defstruct} can specify zero or more
- @i{slot-options}.
- A @i{slot-option} consists of a pair of a keyword and a value
- (which is not a form to be evaluated, but the value itself). For example:
- @example
- (defstruct ship
- (x-position 0.0 :type short-float)
- (y-position 0.0 :type short-float)
- (x-velocity 0.0 :type short-float)
- (y-velocity 0.0 :type short-float)
- (mass *default-ship-mass* :type short-float :read-only t))
- @end example
- This specifies that each slot always contains a @i{short float},
- and that the last slot cannot be altered once a ship is constructed.
- The available slot-options are:
- @table @asis
- @item @t{:type} @i{type}
- This specifies that the contents of the
- slot is always of type @i{type}. This is entirely
- analogous to the declaration of a variable or function; it
- effectively declares the result type of the @i{reader} function.
- It is @i{implementation-dependent} whether the @i{type} is checked
- when initializing a slot
- or when assigning to it.
- @i{Type} is not evaluated; it must be a valid @i{type specifier}.
- @item @t{:read-only} @i{x}
- When @i{x} is @i{true},
- this specifies that this slot cannot be
- altered; it will always contain the value supplied at construction time.
- @b{setf} will not accept the @i{reader} function for this slot.
- If @i{x} is @i{false}, this slot-option has no effect.
- @i{X} is not evaluated.
- When this option is @i{false} or unsupplied,
- it is @i{implementation-dependent} whether the ability to @i{write}
- the slot is implemented by a @i{setf function} or a @i{setf expander}.
- @end table
- The following keyword options are available for use with @b{defstruct}.
- A @b{defstruct} option can be either a keyword or a @i{list}
- of a keyword and arguments for that keyword;
- specifying the keyword by itself is equivalent to specifying a list consisting of
- the keyword and no arguments.
- The syntax for @b{defstruct} options differs from the pair syntax
- used for slot-options. No part of any of these options is evaluated.
- @table @asis
- @item @t{:conc-name}
- This provides for automatic prefixing of names of @i{reader} (or @i{access}) functions.
- The default behavior is to begin the names of all the @i{reader} functions of
- a structure with the name of the structure followed by a hyphen.
- @t{:conc-name} supplies an alternate
- prefix to be used. If a hyphen is to be used as a separator,
- it must be supplied as part of the prefix.
- If @t{:conc-name} is @b{nil} or no argument is supplied,
- then no prefix is used;
- then the names of the @i{reader} functions
- are the same as the slot names.
- If a @i{non-nil} prefix is given,
- the name of the @i{reader} @i{function} for each slot is constructed by
- concatenating that prefix and the name of the slot, and interning the resulting
- @i{symbol} in the @i{package} that is current at the time the
- @b{defstruct} form is expanded.
- Note that no matter what is supplied for @t{:conc-name},
- slot keywords that match the slot names with no prefix attached are used
- with a constructor function.
- The @i{reader} function name is used
- in conjunction with @b{setf}. Here is an example:
- @example
- (defstruct (door (:conc-name dr-)) knob-color width material) @result{} DOOR
- (setq my-door (make-door :knob-color 'red :width 5.0))
- @result{} #S(DOOR :KNOB-COLOR RED :WIDTH 5.0 :MATERIAL NIL)
- (dr-width my-door) @result{} 5.0
- (setf (dr-width my-door) 43.7) @result{} 43.7
- (dr-width my-door) @result{} 43.7
- @end example
- Whether or not the @t{:conc-name} option is explicitly supplied,
- the following rule governs name conflicts of generated @i{reader}
- (or @i{accessor}) names:
- For any @i{structure} @i{type} S_1
- having a @i{reader} function named R for a slot named X_1
- that is inherited by another @i{structure} @i{type} S_2
- that would have a @i{reader} function with the same name R for a slot named X_2,
- no definition for R is generated by the definition of S_2;
- instead, the definition of R is inherited from the definition of S_1.
- (In such a case, if X_1 and X_2 are different slots,
- the @i{implementation} might signal a style warning.)
- @item @t{:constructor}
- This option takes zero, one, or two arguments.
- If at least one argument is supplied and the first argument is not @b{nil}, then
- that argument is a @i{symbol} which specifies the name of the
- constructor function. If the argument is not supplied (or if the option itself is not
- supplied), the name of the constructor is produced by concatenating the
- string @t{"MAKE-"} and the name of the structure, interning the name
- in whatever @i{package} is current at the time @b{defstruct}
- is expanded. If the argument is provided and is @b{nil},
- no constructor function is defined.
- If @t{:constructor} is given as
- @t{(:constructor @i{name} @i{arglist})},
- then instead of making a keyword
- driven constructor function, @b{defstruct}
- defines a ``positional'' constructor function,
- taking arguments whose meaning is determined by the argument's position
- and possibly by keywords.
- @i{Arglist} is used to describe what the arguments to the
- constructor will be. In the simplest case something like
- @t{(:constructor make-foo (a b c))} defines @t{make-foo} to be
- a three-argument
- constructor function whose arguments are used to initialize the
- slots named @t{a}, @t{b}, and @t{c}.
- Because a constructor of this type operates ``By Order of Arguments,''
- it is sometimes known as a ``boa constructor.''
- For information on how the @i{arglist} for a ``boa constructor'' is
- processed, see @ref{Boa Lambda Lists}.
- It is permissible to use the
- @t{:constructor} option more than once, so that you can define several
- different constructor functions, each taking different parameters.
- [Reviewer Note by Barmar: What about (:constructor) and (:constructor nil).
- Should we worry about it?]
- @b{defstruct} creates the default-named keyword constructor function
- only if no explicit @t{:constructor} options are specified, or if the
- @t{:constructor} option is specified without a @i{name} argument.
- @t{(:constructor nil)} is meaningful only when there are no other
- @t{:constructor} options specified. It prevents @b{defstruct}
- from generating any constructors at all.
- Otherwise, @b{defstruct} creates a constructor function corresponding
- to each supplied @t{:constructor} option. It is permissible to specify
- multiple keyword constructor functions as well as multiple
- ``boa constructors''.
- @item @t{:copier}
- This option takes one argument, a @i{symbol},
- which specifies the name of the copier
- function. If the argument is not provided or if the option itself is not
- provided, the name of the copier is produced by concatenating the
- string @t{"COPY-"} and the name of the structure, interning the name
- in whatever @i{package} is current at the time @b{defstruct}
- is expanded.
- If the argument is provided and is @b{nil}, no copier function is defined.
- The automatically defined copier function is a function of
- one @i{argument},
- which must be of the structure type being defined.
- The copier function creates a @i{fresh}
- structure that has the same @i{type} as its @i{argument},
- and that has the @i{same} component values as the original
- structure; that is, the component values are not copied recursively.
- If the @b{defstruct} @t{:type} option was not used,
- the following equivalence applies:
- @example
- (@i{copier-name} x) = (copy-structure (the @i{structure-name} x))
- @end example
- @item @t{:include}
- This option is used for building a new structure definition as
- an extension of another structure definition. For example:
- @example
- (defstruct person name age sex)
- @end example
- To make a new structure to represent an astronaut
- that has the
- attributes of name, age, and sex, and @i{functions}
- that operate on @t{person} structures, @t{astronaut} is defined
- with @t{:include} as follows:
- @example
- (defstruct (astronaut (:include person)
- (:conc-name astro-))
- helmet-size
- (favorite-beverage 'tang))
- @end example
- @t{:include} causes the structure being defined
- to have the same slots as the included structure.
- This is done in such a way
- that the @i{reader} functions for the included
- structure also work on the structure being defined.
- In this example, an
- @t{astronaut} therefore has five slots: the three defined in
- @t{person} and the two defined in @t{astronaut}
- itself. The @i{reader} functions defined by the @t{person} structure
- can be applied to instances of the @t{astronaut} structure, and they
- work correctly.
- Moreover, @t{astronaut} has its own @i{reader} functions for
- components defined by the @t{person} structure.
- The following examples illustrate the
- use of @t{astronaut} structures:
- @example
- (setq x (make-astronaut :name 'buzz
- :age 45.
- :sex t
- :helmet-size 17.5))
- (person-name x) @result{} BUZZ
- (astro-name x) @result{} BUZZ
- (astro-favorite-beverage x) @result{} TANG
- @end example
- @example
- (reduce #'+ astros :key #'person-age) ; obtains the total of the ages
- ; of the possibly empty
- ; sequence of astros
- @end example
- The difference between the @i{reader} functions @t{person-name} and @t{astro-name}
- is that @t{person-name} can be correctly applied to any @t{person},
- including an @t{astronaut}, while @t{astro-name} can be correctly
- applied only to an @t{astronaut}. An implementation might
- check for incorrect use of @i{reader} functions.
- At most one @t{:include} can be supplied in a single @b{defstruct}.
- The argument to @t{:include} is required and must be the
- name of some previously defined structure. If the structure being
- defined has no @t{:type} option, then the included structure must
- also have had no @t{:type} option supplied for it.
- If the structure being defined has a @t{:type} option,
- then the included structure must have been declared with a @t{:type}
- option specifying the same representation @i{type}.
- If no @t{:type} option is involved, then
- the structure name of the including structure definition
- becomes the name of a @i{data type}, and therefore
- a valid @i{type specifier} recognizable by @b{typep}; it becomes
- a @i{subtype} of the included structure.
- In the above example,
- @t{astronaut} is a @i{subtype} of @t{person}; hence
- @example
- (typep (make-astronaut) 'person) @result{} @i{true}
- @end example
- indicating that all operations on persons also
- work on astronauts.
- The structure using @t{:include} can specify default values or
- slot-options for the included slots different from those the included
- structure specifies, by giving the @t{:include} option as:
- @example
- (:include @i{included-structure-name} @{@i{slot-description}@}{*})
- @end example
- Each @i{slot-description} must have a @i{slot-name}
- that is the same
- as that of some slot in the included structure.
- If a @i{slot-description} has no @i{slot-initform},
- then in the new structure the slot has no initial value.
- Otherwise its initial value form is replaced by
- the @i{slot-initform} in the @i{slot-description}.
- A normally writable slot can 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 @i{type} is supplied for a slot, it must be
- a @i{subtype} of
- the
- @i{type} specified in the included structure.
- For example, if the
- default age for an astronaut is @t{45}, then
- @example
- (defstruct (astronaut (:include person (age 45)))
- helmet-size
- (favorite-beverage 'tang))
- @end example
- If @t{:include} is used with the @t{:type}
- option, then the effect is first to skip over as many representation
- elements as needed to represent the included structure, then to
- skip over any additional elements supplied by the @t{:initial-offset}
- option, and then to begin allocation of elements from that point.
- For example:
- @example
- (defstruct (binop (:type list) :named (:initial-offset 2))
- (operator '? :type symbol)
- operand-1
- operand-2) @result{} BINOP
- (defstruct (annotated-binop (:type list)
- (:initial-offset 3)
- (:include binop))
- commutative associative identity) @result{} ANNOTATED-BINOP
- (make-annotated-binop :operator '*
- :operand-1 'x
- :operand-2 5
- :commutative t
- :associative t
- :identity 1)
- @result{} (NIL NIL BINOP * X 5 NIL NIL NIL T T 1)
- @end example
- The first two @b{nil} elements stem from the @t{:initial-offset} of @t{2}
- in the definition of @t{binop}. The next four elements contain the
- structure name and three slots for @t{binop}. The next three @b{nil} elements
- stem from the @t{:initial-offset} of @t{3} in the definition of
- @t{annotated-binop}. The last three list elements contain the additional
- slots for an @t{annotated-binop}.
- @item @t{:initial-offset}
- @t{:initial-offset} instructs @b{defstruct} to skip over a certain
- number of slots before it starts allocating the slots described in the
- body. This option's argument is the number of slots @b{defstruct}
- should skip. @t{:initial-offset} can be used only if @t{:type} is also supplied.
- [Reviewer Note by Barmar: What are initial values of the skipped slots?]
- @t{:initial-offset} allows
- slots to be allocated beginning at a representational
- element other than the first. For example, the form
- @example
- (defstruct (binop (:type list) (:initial-offset 2))
- (operator '? :type symbol)
- operand-1
- operand-2) @result{} BINOP
- @end example
- would result in the following behavior for @t{make-binop}:
- @example
- (make-binop :operator '+ :operand-1 'x :operand-2 5)
- @result{} (NIL NIL + X 5)
- (make-binop :operand-2 4 :operator '*)
- @result{} (NIL NIL * NIL 4)
- @end example
- The selector functions
- @t{binop-operator}, @t{binop-operand-1},
- and @t{binop-operand-2} would be essentially equivalent to @b{third},
- @b{fourth}, and @b{fifth}, respectively.
- Similarly, the form
- @example
- (defstruct (binop (:type list) :named (:initial-offset 2))
- (operator '? :type symbol)
- operand-1
- operand-2) @result{} BINOP
- @end example
- would result in the following behavior for @t{make-binop}:
- @example
- (make-binop :operator '+ :operand-1 'x :operand-2 5) @result{} (NIL NIL BINOP + X 5)
- (make-binop :operand-2 4 :operator '*) @result{} (NIL NIL BINOP * NIL 4)
- @end example
- The first two @b{nil} elements stem from the @t{:initial-offset} of @t{2}
- in the definition of @t{binop}. The next four elements contain the
- structure name and three slots for @t{binop}.
- @item @t{:named}
- @t{:named} specifies that the structure is named.
- If no @t{:type} is supplied,
- then the structure is always named.
- For example:
- @example
- (defstruct (binop (:type list))
- (operator '? :type symbol)
- operand-1
- operand-2) @result{} BINOP
- @end example
- This defines a constructor function @t{make-binop} and three
- selector functions, namely @t{binop-operator}, @t{binop-operand-1},
- and @t{binop-operand-2}. (It does not, however, define a predicate
- @t{binop-p}, for reasons explained below.)
- The effect of @t{make-binop} is simply to construct a list of length three:
- @example
- (make-binop :operator '+ :operand-1 'x :operand-2 5) @result{} (+ X 5)
- (make-binop :operand-2 4 :operator '*) @result{} (* NIL 4)
- @end example
- It is just like the function @t{list} except that it takes
- keyword arguments and performs slot defaulting appropriate to the @t{binop}
- conceptual data type. Similarly, the selector functions
- @t{binop-operator}, @t{binop-operand-1},
- and @t{binop-operand-2} are essentially equivalent to @b{car},
- @b{cadr}, and @b{caddr}, respectively. They might not be
- completely equivalent because,
- for example, an implementation would be justified in adding error-checking
- code to ensure that the argument to each selector function is a length-3
- list.
- @t{binop} is a conceptual data type in that it is not made a part of
- the @r{Common Lisp} type system. @b{typep} does not recognize @t{binop} as
- a @i{type specifier}, and @b{type-of} returns @t{list} when
- given a @t{binop} structure. There is no way to distinguish a data
- structure constructed by @t{make-binop} from any other @i{list} that
- happens to have the correct structure.
- There is not any way to recover the structure name @t{binop} from
- a structure created by @t{make-binop}. This can only be done
- if the structure is named.
- A named structure has the property that, given an instance of the
- structure, the structure name (that names the type) can be reliably
- recovered. For structures defined
- with no @t{:type} option, the structure name actually becomes part
- of the @r{Common Lisp} data-type system. @b{type-of},
- when applied to such a structure, returns the structure name
- as the @i{type} of the @i{object};
- @b{typep} recognizes
- the structure name as a valid @i{type specifier}.
- For structures defined with a @t{:type} option, @b{type-of}
- returns a @i{type specifier} such as @t{list} or @t{(vector t)},
- depending on the type supplied to the @t{:type} option.
- The structure name does not become a valid @i{type specifier}.
- However,
- if the @t{:named} option is also supplied, then the first component
- of the structure (as created by a @b{defstruct} constructor function)
- always contains the structure name. This allows the structure name
- to be recovered from an instance of the structure and allows a reasonable
- predicate for the conceptual type to be defined:
- the automatically defined
- @i{name-p} predicate for the structure operates by first
- checking that its argument is of the proper type (@b{list},
- @t{(vector t)},
- or whatever) and then checking whether the first component contains
- the appropriate type name.
- Consider the @t{binop} example shown above, modified only to
- include the @t{:named} option:
- @example
- (defstruct (binop (:type list) :named)
- (operator '? :type symbol)
- operand-1
- operand-2) @result{} BINOP
- @end example
- As before, this defines a constructor function @t{make-binop} and three
- selector functions @t{binop-operator}, @t{binop-operand-1},
- and @t{binop-operand-2}. It also defines a predicate @t{binop-p}.
- The effect of @t{make-binop} is now to construct a list of length four:
- @example
- (make-binop :operator '+ :operand-1 'x :operand-2 5) @result{} (BINOP + X 5)
- (make-binop :operand-2 4 :operator '*) @result{} (BINOP * NIL 4)
- @end example
- The structure has the same layout as before except that the structure name
- @t{binop} is included as the first list element.
- The selector functions
- @t{binop-operator}, @t{binop-operand-1},
- and @t{binop-operand-2} are essentially equivalent to @b{cadr},
- @b{caddr}, and @b{cadddr}, respectively.
- The predicate @t{binop-p} is more or less equivalent to this
- definition:
- @example
- (defun binop-p (x)
- (and (consp x) (eq (car x) 'binop))) @result{} BINOP-P
- @end example
- The name @t{binop} is still not a valid @i{type specifier} recognizable
- to @b{typep}, but at least there is a way of distinguishing @t{binop}
- structures from other similarly defined structures.
- @item @t{:predicate}
- This option takes one argument, which specifies the name of the type predicate.
- If the argument is not supplied or if the option itself is not
- supplied, the name of the predicate is made by concatenating the
- name of the structure to the string @t{"-P"}, interning the name
- in whatever @i{package} is current at the time @b{defstruct}
- is expanded.
- If the argument is provided and is @b{nil}, no predicate is defined.
- A predicate can be defined only if the structure is named;
- if @t{:type} is supplied and @t{:named} is not supplied,
- then @t{:predicate} must either be unsupplied or have the value @b{nil}.
- @item @t{:print-function}, @t{:print-object}
- The @t{:print-function} and @t{:print-object}
- options
- specify that a @b{print-object}
- @i{method} for @i{structures} of type @i{structure-name} should be generated.
- These options are not synonyms, but do perform a similar service;
- the choice of which option (@t{:print-function} or @t{:print-object}) is used
- affects how the function named @i{printer-name} is called.
- Only one of these options may be used, and
- these options may be used only if @t{:type} is not supplied.
- If the @t{:print-function} option is used,
- then when a structure of type @i{structure-name} is to be printed,
- the designated printer function is called on three @i{arguments}:
- @table @asis
- @item --
- the structure to be printed
- (a @i{generalized instance} of @i{structure-name}).
- @item --
- a @i{stream} to print to.
- @item --
- an @i{integer} indicating the current depth.
- The magnitude of this integer may vary between @i{implementations};
- however, it can reliably be compared against @b{*print-level*}
- to determine whether depth abbreviation is appropriate.
- @end table
- Specifying @t{(:print-function @i{printer-name})}
- is approximately equivalent to specifying:
- @example
- (defmethod print-object ((object @i{structure-name}) stream)
- (funcall (function @i{printer-name}) object stream <<@i{current-print-depth}>>))
- @end example
- where the <<@i{current-print-depth}>> represents the printer's belief of
- how deep it is currently printing. It is @i{implementation-dependent}
- whether <<@i{current-print-depth}>> is always 0 and @i{*print-level*},
- if @i{non-nil}, is re-bound to successively smaller values as printing
- descends recursively, or whether @i{current-print-depth} varies in
- value as printing descends recursively and @i{*print-level*} remains
- constant during the same traversal.
- If the @t{:print-object} option is used, then
- when a structure of type @i{structure-name} is to be printed,
- the designated printer function is called on two arguments:
- @table @asis
- @item --
- the structure to be printed.
- @item --
- the stream to print to.
- @end table
- Specifying @t{(:print-object @i{printer-name})} is equivalent to specifying:
- @example
- (defmethod print-object ((object @i{structure-name}) stream)
- (funcall (function @i{printer-name}) object stream))
- @end example
- If no @t{:type} option is supplied,
- and if either a @t{:print-function} or a @t{:print-object} option is supplied,
- and if no @i{printer-name} is supplied,
- then a @b{print-object} @i{method} @i{specialized} for @i{structure-name}
- is generated that calls a function that implements the default printing behavior for
- structures using @t{#S} notation; see @ref{Printing Structures}.
- If neither a @t{:print-function}
- nor a @t{:print-object} option
- is supplied,
- then @b{defstruct} does not generate a @b{print-object} @i{method}
- @i{specialized} for @i{structure-name} and some default behavior is inherited
- either from a structure named in an @t{:include} option
- or from the default behavior for printing structures;
- see the @i{function} @b{print-object} and @ref{Printing Structures}.
- When @b{*print-circle*} is @i{true},
- a user-defined print function can print @i{objects}
- to the supplied @i{stream} using
- @b{write},
- @b{prin1},
- @b{princ},
- or @b{format}
- and expect circularities to be detected and printed using the @t{#@i{n}#} syntax.
- This applies to @i{methods} on @b{print-object} in addition to
- @t{:print-function} options.
- If a user-defined print function prints to a @i{stream} other than the one
- that was supplied, then circularity detection starts over for that @i{stream}.
- See the @i{variable} @b{*print-circle*}.
- @item @t{:type}
- @t{:type} explicitly specifies the representation to be used for
- the structure. Its argument must be one of these @i{types}:
- @table @asis
- @item @b{vector}
- This produces the same result as specifying @t{(vector t)}.
- The structure is represented
- as a general @i{vector}, storing components as vector elements.
- The first component is vector
- element 1 if the structure is @t{:named}, and element 0 otherwise.
- [Reviewer Note by Barmar: Do any implementations create non-simple vectors?]
- @item @t{(vector @i{element-type})}
- The structure is represented as a (possibly specialized) @i{vector}, storing
- components as vector elements. Every component must be of a @i{type}
- that can be stored in a @i{vector} of the @i{type} specified.
- The first component is vector
- element 1 if the structure is @t{:named}, and element 0 otherwise.
- The structure can be @t{:named} only if the @i{type} @b{symbol}
- is a @i{subtype} of the supplied @i{element-type}.
- @item @b{list}
- The structure is represented as a @i{list}.
- The first component is the @i{cadr} if the structure is @t{:named},
- and the @i{car} if it is not @t{:named}.
- @end table
- Specifying this option has the effect of forcing
- a specific representation and of forcing the components to be
- stored in the order specified in @b{defstruct}
- in corresponding successive elements of the specified representation.
- It also prevents the structure name from becoming a valid
- @i{type specifier} recognizable by @b{typep}.
- For example:
- @example
- (defstruct (quux (:type list) :named) x y)
- @end example
- should make a constructor that builds a @i{list} exactly like the one
- that @b{list} produces,
- with @t{quux} as its @i{car}.
- If this type is defined:
- @example
- (deftype quux () '(satisfies quux-p))
- @end example
- then this form
- @example
- (typep (make-quux) 'quux)
- @end example
- should return precisely what this one does
- @example
- (typep (list 'quux nil nil) 'quux)
- @end example
- If @t{:type} is not supplied,
- the structure is represented as an @i{object} of @i{type} @b{structure-object}.
- @b{defstruct} without a @t{:type} option defines a @i{class} with
- the structure name as its name. The @i{metaclass} of structure
- @i{instances} is @b{structure-class}.
- @end table
- The consequences of redefining a @b{defstruct} structure are undefined.
- In the case where no @b{defstruct} options have been supplied,
- the following functions are automatically defined to operate
- on instances of the new structure:
- @table @asis
- @item Predicate
- A predicate with the name @t{@i{structure-name}-p} is defined to
- test membership in the structure type. The predicate
- @t{(@i{structure-name}-p @i{object})} is @i{true} if an @i{object}
- is of this @i{type}; otherwise it is @i{false}. @b{typep} can also
- be used with the name of the new @i{type} to test whether an
- @i{object}
- belongs to the @i{type}.
- Such a function call has the form
- @t{(typep @i{object} '@i{structure-name})}.
- @item Component reader functions
- @i{Reader} functions are defined to @i{read} the components of the
- structure. For each slot name, there is a corresponding
- @i{reader} function with the name @t{@i{structure-name}-@i{slot-name}}.
- This function @i{reads} the contents of that slot.
- Each @i{reader} function takes one argument, which is
- an instance of the structure type.
- @b{setf} can be used with any of these @i{reader} functions
- to alter the slot contents.
- @item Constructor function
- A constructor function with the name @t{make-@i{structure-name}}
- is defined. This function creates and returns new
- instances of the structure type.
- @item Copier function
- A copier function with the name @t{copy-@i{structure-name}} is defined.
- The copier function takes an object of the structure type and creates a
- new object of the same type that is a copy of the first. The copier
- function creates a new structure with the same component entries
- as the original. Corresponding components of the two structure instances
- are @b{eql}.
- @end table
- If a @b{defstruct} @i{form} appears as a @i{top level form},
- the @i{compiler} must make the @i{structure} @i{type} name recognized
- as a valid @i{type} name in subsequent declarations (as for @b{deftype})
- and make the structure slot readers known to @b{setf}. In addition, the
- @i{compiler} must save enough information about the @i{structure} @i{type}
- so that further @b{defstruct} definitions can use @t{:include} in a subsequent
- @b{deftype} in the same @i{file} to refer to the @i{structure} @i{type} name.
- The functions which @b{defstruct} generates are not defined
- in the compile time environment, although the @i{compiler} may save enough
- information about the functions to code subsequent calls inline.
- The @t{#S} @i{reader macro} might or might not recognize the newly defined
- @i{structure} @i{type} name at compile time.
- @subsubheading Examples::
- An example of a structure definition follows:
- @example
- (defstruct ship
- x-position
- y-position
- x-velocity
- y-velocity
- mass)
- @end example
- This declares that every @t{ship} is an @i{object}
- with five named components.
- The evaluation of this form does the following:
- @table @asis
- @item 1.
- It defines @t{ship-x-position} to be a function
- of one argument, a ship, that returns the @t{x-position}
- of the ship; @t{ship-y-position}
- and the other components are given similar function definitions.
- These functions are called the @i{access} functions, as they
- are used to @i{access} elements of the structure.
- @item 2.
- @t{ship} becomes the name of a @i{type} of which instances
- of ships are elements. @t{ship} becomes acceptable to @b{typep},
- for example; @t{(typep x 'ship)} is @i{true} if @t{x} is a ship
- and false if @t{x} is any @i{object} other than a ship.
- @item 3.
- A function named @t{ship-p} of
- one argument is defined; it is a predicate
- that is @i{true} if its argument is a ship and is @i{false} otherwise.
- @item 4.
- A function called @t{make-ship} is defined that, when invoked,
- creates a data structure with five components, suitable for use with
- the @i{access} functions. Thus executing
- @example
- (setq ship2 (make-ship))
- @end example
- sets @t{ship2} to a newly created @t{ship} @i{object}.
- One can supply the initial values of any desired component in the call
- to @t{make-ship} by using keyword arguments in this way:
- @example
- (setq ship2 (make-ship :mass *default-ship-mass*
- :x-position 0
- :y-position 0))
- @end example
- This constructs a new ship and initializes three of its components.
- This function is called the ``constructor function''
- because it constructs a new structure.
- @item 5.
- A function called @t{copy-ship} of one argument
- is defined that, when given a @t{ship} @i{object},
- creates a new @t{ship} @i{object} that is a copy of the given one.
- This function is called the ``copier function.''
- @end table
- @b{setf} can be used to alter the components of a @t{ship}:
- @example
- (setf (ship-x-position ship2) 100)
- @end example
- This alters the @t{x-position} of @t{ship2} to be @t{100}.
- This works because @b{defstruct} behaves as if
- it generates an appropriate @b{defsetf}
- for each @i{access} function.
- @example
- ;;;
- ;;; Example 1
- ;;; define town structure type
- ;;; area, watertowers, firetrucks, population, elevation are its components
- ;;;
- (defstruct town
- area
- watertowers
- (firetrucks 1 :type fixnum) ;an initialized slot
- population
- (elevation 5128 :read-only t)) ;a slot that can't be changed
- @result{} TOWN
- ;create a town instance
- (setq town1 (make-town :area 0 :watertowers 0)) @result{} #S(TOWN...)
- ;town's predicate recognizes the new instance
- (town-p town1) @result{} @i{true}
- ;new town's area is as specified by make-town
- (town-area town1) @result{} 0
- ;new town's elevation has initial value
- (town-elevation town1) @result{} 5128
- ;setf recognizes reader function
- (setf (town-population town1) 99) @result{} 99
- (town-population town1) @result{} 99
- ;copier function makes a copy of town1
- (setq town2 (copy-town town1)) @result{} #S(TOWN...)
- (= (town-population town1) (town-population town2)) @result{} @i{true}
- ;since elevation is a read-only slot, its value can be set only
- ;when the structure is created
- (setq town3 (make-town :area 0 :watertowers 3 :elevation 1200))
- @result{} #S(TOWN...)
- ;;;
- ;;; Example 2
- ;;; define clown structure type
- ;;; this structure uses a nonstandard prefix
- ;;;
- (defstruct (clown (:conc-name bozo-))
- (nose-color 'red)
- frizzy-hair-p polkadots) @result{} CLOWN
- (setq funny-clown (make-clown)) @result{} #S(CLOWN)
- ;use non-default reader name
- (bozo-nose-color funny-clown) @result{} RED
- (defstruct (klown (:constructor make-up-klown) ;similar def using other
- (:copier clone-klown) ;customizing keywords
- (:predicate is-a-bozo-p))
- nose-color frizzy-hair-p polkadots) @result{} klown
- ;custom constructor now exists
- (fboundp 'make-up-klown) @result{} @i{true}
- ;;;
- ;;; Example 3
- ;;; define a vehicle structure type
- ;;; then define a truck structure type that includes
- ;;; the vehicle structure
- ;;;
- (defstruct vehicle name year (diesel t :read-only t)) @result{} VEHICLE
- (defstruct (truck (:include vehicle (year 79)))
- load-limit
- (axles 6)) @result{} TRUCK
- (setq x (make-truck :name 'mac :diesel t :load-limit 17))
- @result{} #S(TRUCK...)
- ;vehicle readers work on trucks
- (vehicle-name x)
- @result{} MAC
- ;default taken from :include clause
- (vehicle-year x)
- @result{} 79
- (defstruct (pickup (:include truck)) ;pickup type includes truck
- camper long-bed four-wheel-drive) @result{} PICKUP
- (setq x (make-pickup :name 'king :long-bed t)) @result{} #S(PICKUP...)
- ;:include default inherited
- (pickup-year x) @result{} 79
- ;;;
- ;;; Example 4
- ;;; use of BOA constructors
- ;;;
- (defstruct (dfs-boa ;BOA constructors
- (:constructor make-dfs-boa (a b c))
- (:constructor create-dfs-boa
- (a &optional b (c 'cc) &rest d &aux e (f 'ff))))
- a b c d e f) @result{} DFS-BOA
- ;a, b, and c set by position, and the rest are uninitialized
- (setq x (make-dfs-boa 1 2 3)) @result{} #(DFS-BOA...)
- (dfs-boa-a x) @result{} 1
- ;a and b set, c and f defaulted
- (setq x (create-dfs-boa 1 2)) @result{} #(DFS-BOA...)
- (dfs-boa-b x) @result{} 2
- (eq (dfs-boa-c x) 'cc) @result{} @i{true}
- ;a, b, and c set, and the rest are collected into d
- (setq x (create-dfs-boa 1 2 3 4 5 6)) @result{} #(DFS-BOA...)
- (dfs-boa-d x) @result{} (4 5 6)
- @end example
- @subsubheading Exceptional Situations::
- If any two slot names (whether present directly or inherited by the @t{:include} option)
- are the @i{same} under @b{string=},
- @b{defstruct} should signal an error of @i{type} @b{program-error}.
- The consequences are undefined if the @i{included-structure-name}
- does not name a @i{structure type}.
- @subsubheading See Also::
- @ref{documentation; (setf documentation)}
- ,
- @ref{print-object}
- ,
- @ref{setf; psetf}
- ,
- @ref{subtypep}
- ,
- @ref{type-of}
- ,
- @ref{typep}
- ,
- @ref{Compilation}
- @subsubheading Notes::
- The @i{printer-name} should observe the values of
- such printer-control variables as @b{*print-escape*}.
- The restriction against issuing a warning for type mismatches between
- a @i{slot-initform} and the corresponding slot's @t{:type} option is
- necessary because a @i{slot-initform} must be specified in order to
- specify slot options; in some cases, no suitable default may exist.
- The mechanism by which @b{defstruct} arranges for slot accessors to
- be usable with @b{setf} is @i{implementation-dependent};
- for example, it may use @i{setf functions}, @i{setf expanders}, or
- some other @i{implementation-dependent} mechanism known to that
- @i{implementation}'s @i{code} for @b{setf}.
- @node copy-structure, , defstruct, Structures Dictionary
- @subsection copy-structure [Function]
- @code{copy-structure} @i{structure} @result{} @i{copy}
- @subsubheading Arguments and Values::
- @i{structure}---a @i{structure}.
- @i{copy}---a copy of the @i{structure}.
- @subsubheading Description::
- Returns a @i{copy}_6 of the @i{structure}.
- Only the @i{structure} itself is copied; not the values of the slots.
- @subsubheading See Also::
- the @t{:copier} option to
- @ref{defstruct}
- @subsubheading Notes::
- The @i{copy} is the @i{same} as the given @i{structure}
- under @b{equalp}, but not under @b{equal}.
- @c end of including dict-structures
- @c %**end of chapter
|