(generic functions) need to be defined before they are used.
Nevertheless, the MOP is flexible, and is used for a number of
- things, including: documentation generation (where introspective
- functionality in the MOP is used to extract information from a
- running system); object-relational mapping and other approaches to
- object persistence; alternative backing stores for slots
- (hash-tables or symbols); and programmatic construction of
- metaobjects, for example for IDL compilers and model
- transformations.
+ things, including: documentation generation (where introspection in
+ the MOP is used to extract information from a running system);
+ object-relational mapping and other approaches to object
+ persistence; alternative backing stores for slots (hash-tables or
+ symbols); and programmatic construction of metaobjects, for example
+ for IDL compilers and model transformations.
[ XXX: A picture on MOP flexibility here would be good; I have in my mind
one where an object system is a point and the MOP opens up a blob
there are no restrictions on the metaprogrammer constructing
additional subclasses. Previous work \cite{Newton.Rhodes:2008} has
explored the potential for customizing generic function dispatch
- using extended specializers, but as of that work the metaprogrammer
- must override the entirety of the generic function invocation
- protocol (from =compute-discriminating-function= on down), leading
- to toy implementations and duplicated effort.
+ using extended specializers, but there the metaprogrammer must
+ override the entirety of the generic function invocation protocol
+ (from =compute-discriminating-function= on down), leading to toy
+ implementations and duplicated effort.
This paper introduces a protocol for efficient and controlled
handling of new subclasses of =specializer=. In particular, it
implemented using our protocol, which we describe in section
[[#Protocol]]. For reasons of space, the metaprogram code examples in
this section do not include some of the necessary support code to
- run; complete implementations of each of these cases are included in
- an appendix / in the accompanying repository snapshot / at this
- location.
+ run; complete implementations of each of these cases, along with the
+ integration of this protocol into the SBCL implementation
+ \cite{Rhodes:2008} of Common Lisp, are included in an appendix / in
+ the accompanying repository snapshot / at this location.
A note on terminology: we will attempt to distinguish between the
user of an individual case of generalized dispatch (the
\cite{Newton.Rhodes:2008}; the benefits of the protocol described
here are: that the separation of concerns is complete – method
selection is independent of method combination – and that the
- protocol allows where possible for efficient implementation even
+ protocol allows for efficient implementation where possible, even
when method selection is customized. In an application such as
walking source code, we would expect to encounter special forms
(distinguished by particular atoms in the =car= position) multiple
#+begin_src
(defgeneric walk (form env stack)
(:generic-function-class cons-generic-function))
-(defmethod walk ((expr (cons lambda)) env call-stack)
+(defmethod walk
+ ((expr (cons lambda)) env call-stack)
(let ((lambda-list (cadr expr))
(body (cddr expr)))
(with-checked-bindings
- ((bindings-from-ll lambda-list) env call-stack)
+ ((bindings-from-ll lambda-list)
+ env call-stack)
(dolist (form body)
(walk form env (cons form call-stack))))))
-(defmethod walk ((expr (cons let)) env call-stack)
+(defmethod walk
+ ((expr (cons let)) env call-stack)
(flet ((let-binding (x)
- (walk (cadr x) env (cons (cadr x) call-stack))
- (cons (car x) (make-instance 'binding))))
+ (walk (cadr x) env
+ (cons (cadr x) call-stack))
+ (cons (car x)
+ (make-instance 'binding))))
(with-checked-bindings
- ((mapcar #'let-binding (cadr expr)) env call-stack)
+ ((mapcar #'let-binding (cadr expr))
+ env call-stack)
(dolist (form (cddr expr))
(walk form env (cons form call-stack))))))
#+end_src
it has available to satisfy this request, and sends the best
matching resource in its response.
- For example, a graphical web browser might by default send an
- =Accept= header such as
- =text/html,application/xml;q=0.9,*/*;q=0.8=. This should be
- interpreted as meaning that if for a given resource the server can
- provide content of type =text/html= (i.e. HTML), then it should do
- so. Otherwise, if it can provide =application/xml= content
- (i.e. XML of any schema), then that should be provided; failing
- that, any other content type is acceptable.
+ For example, a graphical web browser might send an =Accept= header
+ of =text/html,application/xml;q=0.9,*/*;q=0.8= for a request of a
+ resource typed in to the URL bar. This should be interpreted as
+ meaning that: if the server can provide content of type =text/html=
+ (i.e. HTML) for that resource, then it should do so. Otherwise, if
+ it can provide =application/xml= content (i.e. XML of any schema),
+ then that should be provided; failing that, any other content type
+ is acceptable.
In the case where there are static files on the filesystem, and the
web server must merely select between them, there is not much more
#+end_src
The metaprogrammer can then add support for objects representing
- client requesting, such as instances of the =request= class in the
+ client requests, such as instances of the =request= class in the
Hunchentoot web server, by translating these into
=accept-generalizer= instances. The code below implements this, by
defining the computation of a =generalizer= object for a given
(and q (> q 0))))
#+end_src
- The =next= slot in the =accept-generalizer= is present to deal with
+ The =next= slot in the =accept-generalizer= is used to deal with
the case of methods specialized on the classes of objects as well
as on the acceptable media types; there is a method on
=specializer-accepts-generalizer-p= for specializers that are not
applicability of a particular specializer against a given argument
using =specializer-accepts-p=, a new protocol function with
default implementations on =class= and =eql-specializer= to
- implement the expected behaviour. In order to order the methods,
- as required by the protocol, we define a pairwise comparison
- operator =specializer<= which defines an ordering between
- specializers for a given generalizer argument (remembering that
- even in standard CLOS the ordering between =class= specializers
- can change depending on the actual class of the argument).
+ implement the expected behaviour. To order the methods, as
+ required by the protocol, we define a pairwise comparison operator
+ =specializer<= which defines an ordering between specializers for
+ a given generalizer argument (remembering that even in standard
+ CLOS the ordering between =class= specializers can change
+ depending on the actual class of the argument).
The new =compute-applicable-methods-using-generalizers= is the
analogue of the MOP's =compute-applicable-methods-using-classes=.
answer fits in SBCL's 63-bit fixnums – in an attempt to measure the
worst case for generic dispatch, where the work done within the
methods is as small as possible without being meaningless, and in
- particular does not cause allocation or garbage collection to
+ particular does not cause heap allocation or garbage collection to
obscure the picture.
#+begin_src lisp :exports none
context of partial evaluation; for example, \cite{Ruf:1993}
considers generalization in online partial evaluation, where sets of
possible values are represented by a type system construct
- representing an upper bound. The relationship between generalizer
- metaobjects and approximation in type systems could be further
- explored.
+ representing an upper bound. Exploring the relationship between
+ generalizer metaobjects and approximation in type systems might
+ yield strategies for automatically computing suitable generalizers
+ and cache functions for a variety of forms of generalized dispatch.
* Conclusions
:PROPERTIES:
:CUSTOM_ID: Conclusions