).
There is currently no portable, built-in way to access structure slots
given only the name. If your Common Lisp includes an implementation
of CLOS that supports the meta-object protocol specified in the
original X3J13 draft spec (document X3J13/88-003), then it probably will
allow (SLOT-VALUE <object> '<slot-name>); however, not all
implementations of CLOS currently provide this. Lacking this, some
implementations may provide implementation-dependent functions that
allow access to structure slots by name; note that this may cause
saved images to be larger, as some implementations normally open-code
structure accessors and discard slot name information.
While it is not possible to write a fully general STRUCTURE-SLOT function,
it is not very difficult to write version that handles specific structure
types. For instance, after defining:
(defstruct spaceship name captain position velocity)
one may then define:
(defun spaceship-slot (spaceship slot-name)
(ecase slot-name
(name (spaceship-name spaceship))
(captain (spaceship-captain spaceship))
(position (spaceship-position spaceship))
(velocity (spaceship-velocity spaceship))))
or using CLOS (generic functions):
(defgeneric spaceship-slot (spaceship slot-name)
(:method ((x spaceship) (slot (eql :name)))
(spaceship-name x))
(:method ((x spaceship) (slot (eql :captain)))
(spaceship-captain x))
(:method ((x spaceship) (slot (eql :position)))
(spaceship-position x))
(:method ((x spaceship) (slot (eql :velocity)))
(spaceship-velocity x)))
Another popular way to define this is:
(defun spaceship-slot (spaceship slot-name)
(funcall (symbol-function
(find-symbol (format nil "SPACESHIP-~A" slot-name)
#.(package-name *package*)))
spaceship))
I personally recommend the first version. It is likely to be much faster
and more memory efficient than the second version. It's also easy to get
the second one wrong; many people forget to specify the package argument to
FIND-SYMBOL, which can cause incorrect results when the package at run time
is different from the one at compile time. Even my version assumes that
SPACESHIP-SLOT is being defined in a file that is in the same package as
the one containing the structure definition; if this isn't the case,
#.(PACKAGE-NAME *PACKAGE*) should be replaced by a string naming the
correct package.
Another workaround is to define a MY-DEFSTRUCT macro that parses the
defstruct arguments and expands into a call to DEFSTRUCT along with a
definition of the runtime slot-accessor function.
Some non-portable techniques include the use of SYSTEM:STRUCTURE-REF
in Lucid (LCL:STRUCTURE-REF in earlier versions of Lucid) and
EXCL:STRUCTURE-REF in Allegro.
Go Back Up
Go To Previous
Go To Next