Structure slot accessors are efficient only if the compiler is able to
open code them: compiling a call to a structure slot accessor before
the structure is defined, declaring one notinline
, or passing
it as a functional argument to another function causes severe
perfomance degradation.
The most efficient way to access a slot of a standard-object
is
by using slot-value
with a constant slot name argument inside a
defmethod
body, where the variable holding the instance is a
specializer parameter of the method and is never assigned to. The cost
is roughly 1.6 times that of an open coded structure slot accessor.
Second most efficient way is to use a CLOS slot accessor, or
slot-value
with a constant slot name argument, but in
circumstances other than specified above. This may be up to 3 times as
slow as the method described above.
Example:
(defclass foo () ((bar))) ;; Fast: specializer and never assigned to (defmethod quux ((foo foo) new) (let ((old (slot-value foo 'bar))) (setf (slot-value foo 'bar) new) old)) ;; Slow: not a specializer (defmethod quux ((foo foo) new) (let* ((temp foo) (old (slot-value temp 'bar))) (setf (slot-value temp 'bar) new) old)) ;; Slow: assignment to FOO (defmethod quux ((foo foo) new) (let ((old (slot-value foo 'bar))) (setf (slot-value foo 'bar) new) (setf foo new) old))
Note that when profiling code such as this, the first few calls to the generic function are not representative, as the dispatch mechanism is lazily set up during those calls.