Common Lisp the Language, 2nd Edition
![]()
Next: Structures of
Explicitly Up: Structures Previous: Defstruct Options
If the :constructor option is given as
(``:constructor``namearglist),
then instead of making a keyword-driven constructor function,
defstruct defines a ``positional’’ constructor function,
taking arguments whose meaning is determined by the argument’s position
rather than by a keyword. The arglist is used to describe what
the arguments to the constructor will be. In the simplest case something
like (``:constructor`` make-foo (a b c)) defines
make-foo to be a three-argument constructor function whose
arguments are used to initialize the slots named a,
b, and c.
In addition, the keywords &optional,
&rest, and &aux are recognized in the
argument list. They work in the way you might expect, but there are a
few fine points worthy of explanation. Consider this example:
(:constructor create-foo
(a &optional b (c 'sea) &rest d &aux e (f 'eff)))
This defines create-foo to be a constructor of one or
more arguments. The first argument is used to initialize the
a slot. The second argument is used to initialize the
b slot. If there isn’t any second argument, then the
default value given in the body of the defstruct (if given)
is used instead. The third argument is used to initialize the
c slot. If there isn’t any third argument, then the symbol
sea is used instead. Any arguments following the third
argument are collected into a list and used to initialize the
d slot. If there are three or fewer arguments, then
nil is placed in the d slot. The
e slot is not initialized; its initial value is
undefined. Finally, the f slot is initialized to contain
the symbol eff.
The actions taken in the b and e cases were
carefully chosen to allow the user to specify all possible behaviors.
Note that the &aux ``variables’’ can be used to
completely override the default initializations given in the body.
With this definition, one can write
(create-foo 1 2)
instead of
(make-foo :a 1 :b 2)
and of course create-foo provides defaulting different
from that of make-foo.
It is permissible to use the :constructor option more
than once, so that you can define several different constructor
functions, each taking different parameters.
Because a constructor of this type operates By Order of Arguments, it is sometimes known as a BOA constructor.

X3J13 voted in January 1989 (DEFSTRUCT-CONSTRUCTOR-KEY-MIXTURE) to
allow &key and &allow-other-keys in
the parameter list of a ``positional’’ constructor. The initialization
of slots corresponding to keyword parameters is performed in the same
manner as for &optional parameters. A variant of the
example shown above illustrates this:
(:constructor create-foo
(a &optional b (c 'sea)
&key p (q 'cue) ((:why y)) ((:you u) 'ewe)
&aux e (f 'eff)))
The treatment of slots a, b,
c, e, and f is the same as in the
original example. In addition, if there is a :p keyword
argument, it is used to initialize the p slot; if there
isn’t any :p keyword argument, then the default value given
in the body of the defstruct (if given) is used instead.
Similarly, if there is a :q keyword argument, it is used to
initialize the q slot; if there isn’t any :q
keyword argument, then the symbol cue is used instead.
In order thoroughly to flog this presumably already dead horse, we
further observe that if there is a :why keyword argument,
it is used to initialize the y slot; otherwise the default
value for slot y is used instead. Similarly, if there is a
:you keyword argument, it is used to initialize the
u slot; otherwise the symbol ewe is used
instead.
If memory serves me correctly, defstruct was included in
the original design for Common Lisp some time before keyword arguments
were approved. The failure of positional constructors to accept keyword
arguments may well have been an oversight on my part; there is no
logical reason to exclude them. I am grateful to X3J13 for rectifying
this.
A remaining difficulty is that the possibility of keyword arguments renders the term ``positional constructor’’ a misnomer. Worse yet, it ruins the term ``BOA constructor.’’ I suggest that they continue to be called BOA constructors, as I refuse to abandon a good pun. (I regret appearing to have more compassion for puns than for horses.)
As part of the same vote X3J13 also changed defstruct to
allow BOA constructors to have parameters (including supplied-p
parameters) that do not correspond to any slot. Such parameters may be
used in subsequent initialization forms in the parameter list. Consider
this example:
(defstruct (ice-cream-factory
(:constructor fabricate-factory
(&key (capacity 5)
location
(local-flavors
(case location
((hawaii) '(pineapple macadamia guava))
((massachusetts) '(lobster baked-bean))
((california) '(ginger lotus avocado
bean-sprout garlic))
((texas) '(jalapeno barbecue))))
(flavors (subseq (append local-flavors
'(vanilla
chocolate
strawberry
pistachio
maple-walnut
peppermint))
0 capacity)))))
(capacity 3)
(flavors '(vanilla chocolate strawberry mango)))
The structure type ice-cream-factory has two
constructors. The standard constructor,
make-ice-cream-factory, takes two keyword arguments named
:capacity and :flavors. For this constructor,
the default for the capacity slot is 3 and the
default list of flavors is America’s favorite threesome and
a dark horse (not a dead one). The BOA constructor
fabricate-factory accepts four different keyword arguments.
The :capacity argument defaults to 5, and the
:flavors argument defaults in a complicated manner based on
the other three. The :local-flavors argument may be
specified directly, or may be allowed to default based on the
:location of the factory. Here are examples of various
factories:
(setq houston (fabricate-factory :capacity 4 :location 'texas))
(setq cambridge (fabricate-factory :location 'massachusetts))
(setq seattle (fabricate-factory :local-flavors '(salmon)))
(setq wheaton (fabricate-factory :capacity 4 :location 'illinois))
(setq pittsburgh (fabricate-factory :capacity 4))
(setq cleveland (make-factory :capacity 4))
(ice-cream-factory-flavors houston)
=> (jalapeno barbecue vanilla chocolate)
(ice-cream-factory-flavors cambridge)
=> (lobster baked-bean vanilla chocolate strawberry)
(ice-cream-factory-flavors seattle)
=> (salmon vanilla chocolate strawberry pistachio)
(ice-cream-factory-flavors wheaton)
=> (vanilla chocolate strawberry pistachio)
(ice-cream-factory-flavors pittsburgh)
=> (vanilla chocolate strawberry pistachio)
(ice-cream-factory-flavors cleveland)
=> (vanilla chocolate strawberry mango)
![]()
Next: Structures of
Explicitly Up: Structures Previous: Defstruct Options
AI.Repository@cs.cmu.edu