incorporating substantial fractions of the Metaobject Protocol as
described.
+ #+CAPTION: MOP Design Space
+ #+LABEL: fig:mopdesign
+ #+ATTR_LATEX: width=\linewidth float
+ [[file:figures/mop-design-space.pdf]]
+
Although it has stood the test of time, the CLOS MOP is neither
without issues (e.g. semantic problems with =make-method-lambda=
\cite{Costanza.Herzeel:2008}; useful functions such as
implement all conceivable variations of object-oriented behaviour.
While metaprogramming offers some possibilities for customization of
the object system behaviour, those possibilities cannot extend
- arbitrarily in all directions. There is still an expectation that
- functionality is implemented with methods on generic functions,
- acting on objects with slots; it is not possible, for example, to
- transparently implement support for “message not understood” as in
- the message-passing paradigm, because the analogue of messages
- (generic functions) need to be defined before they are used.
+ arbitrarily in all directions (conceptually, if a given object
+ system is a point in design space, then a MOP for that object system
+ allows exploration of a region of design space around that point;
+ see figure \ref{fig:mopdesign}). In the case of the CLOS MOP, there is
+ still an expectation that functionality is implemented with methods
+ on generic functions, acting on objects with slots; it is not
+ possible, for example, to transparently implement support for
+ “message not understood” as in the message-passing paradigm, because
+ the analogue of messages (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 introspection in
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
- around that point, and I'm sure I've seen it somewhere but I can't
- remember where. Alternatively, there's Kiczales et al "MOPs: why we
- want them and what else they can do", fig. 2 ]
- [AMOP, page 5] paints that picture, but again, only using words :)
-
One area of functionality where there is scope for customization by
the metaprogrammer is in the mechanics and semantics of method
applicability and dispatch. While in principle AMOP allows
#+CAPTION: Dispatch Comparison
#+LABEL: fig:dispatch
- #+ATTR_LATEX: width=0.9\linewidth float
- [[file:figures/dispatch-comparison.pdf]]
+ #+ATTR_LATEX: width=\linewidth float
+ [[file:figures/dispatch-relationships.pdf]]
The remaining sections in this paper can be read in any order. We
give some motivating examples in section [[#Examples]], including
Our second example of the implementation and use of generalized
specializers is a reimplementation of one of the examples in
\cite{Costanza.etal:2008}: specifically, the factorial function.
- Here, we will perform dispatch based on the =signum= of the
+ Here, dispatch will be performed based on the =signum= of the
argument, and again, at most one method with a =signum= specializer
- will be appliable to any given argument, which makes the structure
+ will be applicable to any given argument, which makes the structure
of the specializer implementation very similar to the =cons=
specializers in the previous section.
(defmethod fact ((n (signum 1))) (* n (fact (1- n))))
#+end_src
- We do not need to include a method on =(signum -1)=, as the
- standard =no-applicable-method= protocol will automatically apply to
- negative real or non-real arguments.
+ The programmer does not need to include a method on =(signum -1)=,
+ as the standard =no-applicable-method= protocol will automatically
+ apply to negative real or non-real arguments.
** Accept HTTP header specializers
:PROPERTIES:
:CUSTOM_ID: Accept
(arg tbnl:request))
(make-instance 'accept-generalizer
:header (tbnl:header-in :accept arg)
- :next (class-of arg)))
+ :next (call-next-method)))
(defmethod specializer-accepts-p
((s accept-specializer)
(o tbnl:request))
(ensure-class nil :direct-superclasses
'(text/html image/webp ...))
#+end_src
- and dispatch operates using those anonymous classes. While
+ and dispatch would operate using those anonymous classes. While
this is possible to do, it is awkward to express content-type
negotiation in this way, as it means that the dispatcher must know
about the universe of mime-types that clients might declare that
filtering paradigm.
Note that in this example, the method on =specializer<= involves a
- nontrivial ordering of methods based on the =q= values specified in
- the accept header (whereas in sections [[#Cons]] and [[#Signum]] only a
+ non-trivial ordering of methods based on the =q= values specified
+ in the accept header (whereas in sections [[#Cons]] and [[#Signum]] only a
single extended specializer could be applicable to any given
argument).
(s string))
(make-instance 'accept-generalizer
:header s
- :next (class-of s)))
+ :next (call-next-method)))
(defmethod specializer-accepts-p
((s accept-specializer) (o string))
(let* ((tree (parse-accept-string o))
:END:
In section [[#Examples]], we have seen a number of code fragments as
- partial implementations of particular non-standard method dispatch,
- using =generalizer= metaobjects to mediate between the methods of
- the generic function and the actual arguments passed to it. In
- section [[#Generalizer metaobjects]], we go into more detail regarding
- these =generalizer= metaobjects, describing the generic function
- invocation protocol in full, and showing how this protocol allows a
- similar form of effective method cacheing as the standard one does.
- In section [[#Generalizer performance]], we show the results of some
- simple performance measurements on our implementation of this
- protocol in the SBCL implementation \cite{Rhodes:2008} of Common
- Lisp to highlight the improvement that this protocol can bring over
- a naïve implementation of generalized dispatch, as well as
- to make the potential for further improvement clear.
+ partial implementations of particular non-standard method dispatch
+ strategies, using =generalizer= metaobjects to mediate between the
+ methods of the generic function and the actual arguments passed to
+ it. In section [[#Generalizer metaobjects]], we go into more detail
+ regarding these =generalizer= metaobjects, describing the generic
+ function invocation protocol in full, and showing how this protocol
+ allows a similar form of effective method cacheing as the standard
+ one does. In section [[#Generalizer performance]], we show the results
+ of some simple performance measurements on our implementation of
+ this protocol in the SBCL implementation \cite{Rhodes:2008} of
+ Common Lisp to highlight the improvement that this protocol can
+ bring over a naïve implementation of generalized dispatch, as well
+ as to make the potential for further improvement clear.
** Generalizer metaobjects
:PROPERTIES:
required arguments in a list to use as a key in an =equal=
hash-table.
- [XXX could we actually compute a suitable hash key using the
+#+begin_comment
+ [could we actually compute a suitable hash key using the
generalizer's class name and initargs?]
+#+end_comment
*** COMMENT
- [X] =generalizer-of-using-class= (NB class of gf not class of object)
cater for filtered dispatch, but they would have to explicitly
modify their method combinations. The Clojure programming language
supports multimethods[fn:5] with a variant of filtered dispatch as
- well as hierachical and identity-based method selectors.
+ well as hierarchical and identity-based method selectors.
In context-oriented programming
\cite{Hirschfeld.etal:2008,Vallejos.etal:2010}, context dispatch
amortized (though there remains a substantial overhead compared with
standard generic-function or regular function calls). We discuss
how the efficiency could be improved below.
-** Future Work
+** Future work
:PROPERTIES:
:CUSTOM_ID: Future Work
:END: