Christophe Weblog Wiki Code Publications Music
more minor corrections
authorChristophe Rhodes <csr21@cantab.net>
Tue, 4 Mar 2014 11:17:56 +0000 (11:17 +0000)
committerChristophe Rhodes <csr21@cantab.net>
Tue, 4 Mar 2014 11:17:56 +0000 (11:17 +0000)
els-specializers.org

index 3d426e1f765c55feb857657421f5e55a8068d35c..a6d2bab9c27cc63a88dc40a76afbe067cd1453e2 100644 (file)
@@ -32,6 +32,8 @@
   \\affaddr{Vilhonkatu 5 A}\\\\
   \\affaddr{FI-00100 Helsinki}\\\\
   \\email{david@lichteblau.com}
+}
+\\maketitle")
 #+end_src
 
 #+begin_abstract
@@ -89,16 +91,18 @@ efficient.
   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.
-  Example of something not doable: handling "message not understood"
-  message from message passing paradigm.
-  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
+  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 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.
 
   [ XXX: A picture on MOP flexibility here would be good; I have in my mind
@@ -192,16 +196,16 @@ efficient.
 
    The programmer code using these specializers is unchanged from
    \cite{Newton.Rhodes:2008}; the benefits of the protocol described
-   here are centered on performance and generality:
-
-   alternative suggestions: modularity/improved code reuse/separation
-   of concerns since e.g. arbitrary method combinations can be used
-
-   in an application such as walking source code, we would expect to
-   encounter special forms (distinguished by particular atoms in the
-   =car= position) multiple times, and hence to dispatch to the same
-   effective method repeatedly.  We discuss this in more detail in
-   section [[#Memoization]]; we present the metaprogrammer code below.
+   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
+   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
+   times, and hence to dispatch to the same effective method
+   repeatedly.  We discuss the efficiency aspects of the protocol in
+   more detail in section [[#Memoization]]; we present the metaprogrammer
+   code to implement the =cons-specializer= below.
 
 #+begin_src lisp
 (defclass cons-specializer (specializer)
@@ -231,19 +235,15 @@ efficient.
   (and (consp o) (eql (car o) (%car s))))
 #+end_src
 
-The code above shows a minimal use of our protocol.  We have
-elided some support code for parsing and unparsing specializers, and
-for handling introspective functions such as finding generic functions
-for a given specializer.  We have also elided methods on the protocol
-function =specializer<=
-
-mention =same-specializer-p=? especially when "only one
-=cons-specializer=" touches on specializer equality.
-
-; for =cons-specializers= here, specializer
-ordering is trivial, as only one =cons-specializer= can ever be
-applicable to any given argument.  See section [[#Accept]] for a case
-where specializer ordering is non-trivial.
+The code above shows a minimal use of our protocol.  We have elided
+some support code for parsing and unparsing specializers, and for
+handling introspective functions such as finding generic functions for
+a given specializer.  We have also elided methods on the protocol
+functions =specializer<= and =same-specializer-p=; for
+=cons-specializer= objects, specializer ordering is trivial, as only
+one =cons-specializer= (up to equality) can ever be applicable to any
+given argument.  See section [[#Accept]] for a case where specializer
+ordering is non-trivial.
 
 As in \cite{Newton.Rhodes:2008}, the programmer can use these
 specializers to implement a modular code walker, where they define one
@@ -272,25 +272,19 @@ unbound variables.
 #+end_src
 
    Note that in this example there is no strict need for
-   =cons-specializer= and =cons-generalizer= to be distinct classes –
-   just as in the normal protocol involving
-   =compute-applicable-methods= and
-   =compute-applicable-methods-using-classes=, the specializer object
-   for mediating dispatch contains the same information as the object
-   representing the equivalence class of objects to which that
-   specializer is applicable: here it is the =car= of the =cons=
-   (which we wrap in a distinct object);
-
-   the previous sentence is rather long and hard to understand
-
-   in the standard dispatch it
-   is the =class= of the object.  This feature also characterizes
-   those use cases where the metaprogrammer could straightforwardly
-   use filtered dispatch \cite{Costanza.etal:2008} to implement their
-   dispatch semantics.  We will see in section [[#Accept]] an example
-   of a case where filtered dispatch is incapable of straightforwardly
-   expressing the dispatch, but first we present our implementation of
-   the motivating case from \cite{Costanza.etal:2008}.
+   =cons-specializer= and =cons-generalizer= to be distinct classes.
+   In standard generic function dispatch, the =class= functions both
+   as the specializer for methods and as the generalizer for generic
+   function arguments; we can think of the dispatch implemented by
+   =cons-specializer= objects as providing for subclasses of the
+   =cons= class distinguished by the =car= of the =cons=.  This
+   analogy also characterizes those use cases where the metaprogrammer
+   could straightforwardly use filtered dispatch
+   \cite{Costanza.etal:2008} to implement their dispatch semantics.
+   We will see in section [[#Accept]] an example of a case where filtered
+   dispatch is incapable of straightforwardly expressing the dispatch,
+   but first we present our implementation of the motivating case from
+   \cite{Costanza.etal:2008}.
 ** SIGNUM specializers
    :PROPERTIES:
    :CUSTOM_ID: Signum
@@ -304,11 +298,11 @@ unbound variables.
    of the specializer implementation very similar to the =cons=
    specializers in the previous section.
 
-   The metaprogrammer may choose to?
-   We have chosen to compare signum values using \texttt{=}, which
-   means that a method with specializer =(signum 1)= will be
-   applicable to positive floating-point arguments (see the first
-   method on =specializer-accepts-generalizer-p= and the method on
+   The metaprogrammer has chosen in the example below to compare
+   signum values using \texttt{=}, which means that a method with
+   specializer =(signum 1)= will be applicable to positive
+   floating-point arguments (see the first method on
+   =specializer-accepts-generalizer-p= and the method on
    =specializer-accepts-p= below).  This leads to one subtle
    difference in behaviour compared to that of the =cons=
    specializers: in the case of =signum= specializers, the /next/
@@ -322,11 +316,10 @@ unbound variables.
   ((%signum :reader %signum :initarg :signum)))
 (defclass signum-generalizer (generalizer)
   ((%signum :reader %signum :initarg :signum)))
-;; Not sure whether I am overlooking something but shouldn't this work:
 (defmethod generalizer-of-using-class
     ((gf signum-generic-function) (arg real))
-    (make-instance 'signum-generalizer
-                   :signum (signum arg)))
+  (make-instance 'signum-generalizer
+                 :signum (signum arg)))
 (defmethod generalizer-equal-hash-key
     ((gf signum-generic-function)
      (g signum-generalizer))
@@ -335,18 +328,13 @@ unbound variables.
     ((gf signum-generic-function)
      (s signum-specializer)
      (g signum-generalizer))
-  ;; Would EQL work here? I'm thinking there might be an invariant of the form
-  ;; (specializer-accepts-p gf o)
-  ;; <=>
-  ;; (specializer-accepts-generalizer-p gf s (generalizer-of-using-class gf o))
-  ;; Or if that wrong, maybe we should explain why.
-  (if (= (%signum s) (%signum g)) ; or EQL?
+  (if (= (%signum s) (%signum g))
       (values t t)
       (values nil t)))
 
 (defmethod specializer-accepts-generalizer-p
     ((gf signum-generic-function)
-     (s sb-mop:specializer)
+     (s specializer)
      (g signum-generalizer))
   (specializer-accepts-generalizer-p
    gf s (class-of (%signum g))))
@@ -436,7 +424,7 @@ unbound variables.
   (values (q (media-type s) (tree g)) t))
 (defmethod specializer-accepts-generalizer-p
     ((gf accept-generic-function)
-     (s specializer) ; other listing has sb-mop:specializer
+     (s specializer)
      (g accept-generalizer))
   (specializer-accepts-generalizer-p
    gf s (next g)))
@@ -485,9 +473,6 @@ unbound variables.
     (and q (> q 0))))
 #+end_src
 
-   In the =next= slot in the previous listing and this listing is not
-   discussed, I think.
-
    This dispatch cannot be implemented using filtered dispatch, except
    by generating anonymous classes with all the right mime-types as
    direct superclasses in dispatch order; the filter would generate
@@ -533,6 +518,17 @@ unbound variables.
          (q (q (media-type s) tree)))
     (and q (> q 0))))
 #+end_src
+
+   The =next= slot in the =accept-generalizer= is present 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
+   of type =accept-specializer= which calls the generic function again
+   with the next generalizer, so that methods specialized on the
+   classes =tbnl:request= and =string= are treated as applicable to
+   corresponding objects, though less specific than methods with
+   =accept-specializer= specializations.
+
 ** COMMENT Pattern / xpattern / regex / optima
    Here's the /really/ interesting bit, but on the other hand we're
    probably going to run out of space, and the full description of