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}
   \\affaddr{Vilhonkatu 5 A}\\\\
   \\affaddr{FI-00100 Helsinki}\\\\
   \\email{david@lichteblau.com}
+}
+\\maketitle")
 #+end_src
 
 #+begin_abstract
 #+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,
   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
   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
 
    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)
 
 #+begin_src lisp
 (defclass cons-specializer (specializer)
@@ -231,19 +235,15 @@ efficient.
   (and (consp o) (eql (car o) (%car s))))
 #+end_src
 
   (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
 
 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
 #+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
 ** 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.
 
    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/
    =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)))
   ((%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))
 (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))
 (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))
     ((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)
       (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))))
      (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)
   (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)))
      (g accept-generalizer))
   (specializer-accepts-generalizer-p
    gf s (next g)))
@@ -485,9 +473,6 @@ unbound variables.
     (and q (> q 0))))
 #+end_src
 
     (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
    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
          (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
 ** 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