Common Lisp the Language, 2nd Edition
Next: Structures of
Explicitly Up: Structures Previous: Defstruct Options
If the :constructor
option is given as
(``:constructor``
name
arglist
)
,
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