The Generic Frame Protocol provides a mechanism for implementations to access efficient iteration mechanisms provided by the underlying FRSs. It does this by providing a means to generate implementation-specific expansions to the iterator macros do-class-direct-instances, do-class-direct-subs, do-class-direct-supers, do-facet-values, do-frame-slots, do-instance-direct-types, do-kb-classes, do-kb-frames, do-kb-instances, do-slot-facets, and do-slot-values. Because the code for these iterator macros is expanded at compile time it is possible to achieve iterations that do not cons at all and pay a price of only a single generic function dispatch per looping construct. Because the code for these constructs is expanded in line at the point of the call, it is necessary to define the implementation-specific forms for these iterators using a GFP-specific macro called defloop-expander, rather than by defining a *-internal method as is the case with all of the GFP generic functions.
defloop-expander (iterator-name (iteration-variable &rest other-args) (body-arg-name) &body expander-body) Macro
The defloop-expander macro defines a means of making an implementation-specific expansion for the iterator iterator-name. Iteration-variable is the loop variable that takes on the value of the current object of the collection of objects over which GFP is iterating. Other-args is the set of other arguments in the primary argument list of the iteration macro. Body-arg-name is the name used within the expander-body to refer to the user-supplied body when the iteration macro is used. For example:
(defloop-expander do-slot-values (value-var frame slot (kb my-kb-class)) (user-code-body) (loop for value-var in (slot-value frame slot) do user-code-body))
will define a loop expander for the iterator macro do-slot-values, which will apply when a use of the looping construct is called with a set of arguments that will select the specializer pattern ((frame t) (slot t) (kb my-kb-class)). The body of the loop uses the special names value-var and user-code-body to denote the current value in the set of values over which we are iterating and the code in the body of the instance of the do-slot-values macro in the user's code. Thus, if in the user's code there is a call of the form:
;; Print out the values of the slot with numbers, one on a line. (let ((count 0)) (do-slot-values (val current-frame interesting-slot) (format t "~&Value ~D = ~S" count val) (incf count)))
then the body of the loop denoted by user-code-body in the loop expander will take on the value
(locally (format t "~&Value ~D = ~S" count val) (incf count))
It is worth noting that because of the expansion of loop-expanders at compile time, it is necessary to compile all user code after the loading of all defloop-expander forms in order for the user's code to be able to benefit from the optimizations provided. Failure to do so will result in only the default loop expander being expanded into the compiled code, which is likely to be significantly more expensive than any implementation-specific expander.