elisp: Generic Functions

 
 12.8 Generic Functions
 ======================
 
 Functions defined using ‘defun’ have a hard-coded set of assumptions
 about the types and expected values of their arguments.  For example, a
 function that was designed to handle values of its argument that are
 either numbers or lists of numbers will fail or signal an error if
 called with a value of any other type, such as a vector or a string.
 This happens because the implementation of the function is not prepared
 to deal with types other than those assumed during the design.
 
    By contrast, object-oriented programs use “polymorphic functions”: a
 set of specialized functions having the same name, each one of which was
 written for a certain specific set of argument types.  Which of the
 functions is actually called is decided at run time based on the types
 of the actual arguments.
 
    Emacs provides support for polymorphism.  Like other Lisp
 environments, notably Common Lisp and its Common Lisp Object System
 (CLOS), this support is based on “generic functions”.  The Emacs generic
 functions closely follow CLOS, including use of similar names, so if you
 have experience with CLOS, the rest of this section will sound very
 familiar.
 
    A generic function specifies an abstract operation, by defining its
 name and list of arguments, but (usually) no implementation.  The actual
 implementation for several specific classes of arguments is provided by
 “methods”, which should be defined separately.  Each method that
 implements a generic function has the same name as the generic function,
 but the method’s definition indicates what kinds of arguments it can
 handle by “specializing” the arguments defined by the generic function.
 These “argument specializers” can be more or less specific; for example,
 a ‘string’ type is more specific than a more general type, such as
 ‘sequence’.
 
    Note that, unlike in message-based OO languages, such as C++ and
 Simula, methods that implement generic functions don’t belong to a
 class, they belong to the generic function they implement.
 
    When a generic function is invoked, it selects the applicable methods
 by comparing the actual arguments passed by the caller with the argument
 specializers of each method.  A method is applicable if the actual
 arguments of the call are compatible with the method’s specializers.  If
 more than one method is applicable, they are combined using certain
 rules, described below, and the combination then handles the call.
 
  -- Macro: cl-defgeneric name arguments [documentation]
           [options-and-methods...] &rest body
      This macro defines a generic function with the specified NAME and
      ARGUMENTS.  If BODY is present, it provides the default
      implementation.  If DOCUMENTATION is present (it should always be),
      it specifies the documentation string for the generic function, in
      the form ‘(:documentation DOCSTRING)’.  The optional
      OPTIONS-AND-METHODS can be one of the following forms:
 
      ‘(declare DECLARATIONS)’
           A declare form, as described in SeeDeclare Form.
      ‘(:argument-precedence-order &rest ARGS)’
           This form affects the sorting order for combining applicable
           methods.  Normally, when two methods are compared during
           combination, method arguments are examined left to right, and
           the first method whose argument specializer is more specific
           will come before the other one.  The order defined by this
           form overrides that, and the arguments are examined according
           to their order in this form, and not left to right.
      ‘(:method [QUALIFIERS...] args &rest body)’
           This form defines a method like ‘cl-defmethod’ does.
 
  -- Macro: cl-defmethod name [qualifier] arguments &rest [docstring]
           body
      This macro defines a particular implementation for the generic
      function called NAME.  The implementation code is given by BODY.
      If present, DOCSTRING is the documentation string for the method.
      The ARGUMENTS list, which must be identical in all the methods that
      implement a generic function, and must match the argument list of
      that function, provides argument specializers of the form ‘(ARG
      SPEC)’, where ARG is the argument name as specified in the
      ‘cl-defgeneric’ call, and SPEC is one of the following specializer
      forms:
 
      ‘TYPE’
           This specializer requires the argument to be of the given
           TYPE, one of the types from the type hierarchy described
           below.
      ‘(eql OBJECT)’
           This specializer requires the argument be ‘eql’ to the given
           OBJECT.
      ‘(head OBJECT)’
           The argument must be a cons cell whose ‘car’ is ‘eql’ to
           OBJECT.
      ‘STRUCT-TAG’
           The argument must be an instance of a class named STRUCT-TAG
           defined with ‘cl-defstruct’ (See(cl)Structures), or of
           one of its parent classes.
 
      Alternatively, the argument specializer can be of the form
      ‘&context (EXPR SPEC)’, in which case the value of EXPR must be
      compatible with the specializer provided by SPEC; SPEC can be any
      of the forms described above.  In other words, this form of
      specializer uses the value of EXPR instead of arguments for the
      decision whether the method is applicable.  For example, ‘&context
      (overwrite-mode (eql t))’ will make the method compatible only when
      ‘overwrite-mode’ is turned on.
 
      The type specializer, ‘(ARG TYPE)’, can specify one of the “system
      types” in the following list.  When a parent type is specified, an
      argument whose type is any of its more specific child types, as
      well as grand-children, grand-grand-children, etc.  will also be
      compatible.
 
      ‘integer’
           Parent type: ‘number’.
      ‘number’
      ‘null’
           Parent type: ‘symbol’
      ‘symbol’
      ‘string’
           Parent type: ‘array’.
      ‘array’
           Parent type: ‘sequence’.
      ‘cons’
           Parent type: ‘list’.
      ‘list’
           Parent type: ‘sequence’.
      ‘marker’
      ‘overlay’
      ‘float’
           Parent type: ‘number’.
      ‘window-configuration’
      ‘process’
      ‘window’
      ‘subr’
      ‘compiled-function’
      ‘buffer’
      ‘char-table’
           Parent type: ‘array’.
      ‘bool-vector’
           Parent type: ‘array’.
      ‘vector’
           Parent type: ‘array’.
      ‘frame’
      ‘hash-table’
      ‘font-spec’
      ‘font-entity’
      ‘font-object’
 
      The optional QUALIFIER allows combining several applicable methods.
      If it is not present, the defined method is a “primary” method,
      responsible for providing the primary implementation of the generic
      function for the specialized arguments.  You can also define
      “auxiliary methods”, by using one of the following values as
      QUALIFIER:
 
      ‘:before’
           This auxiliary method will run before the primary method.
           More accurately, all the ‘:before’ methods will run before the
           primary, in the most-specific-first order.
      ‘:after’
           This auxiliary method will run after the primary method.  More
           accurately, all such methods will run after the primary, in
           the most-specific-last order.
      ‘:around’
           This auxiliary method will run _instead_ of the primary
           method.  The most specific of such methods will be run before
           any other method.  Such methods normally use
           ‘cl-call-next-method’, described below, to invoke the other
           auxiliary or primary methods.
      ‘:extra STRING’
           This allows you to add more methods, distinguished by STRING,
           for the same specializers and qualifiers.
 
    Each time a generic function is called, it builds the “effective
 method” which will handle this invocation by combining the applicable
 methods defined for the function.  The process of finding the applicable
 methods and producing the effective method is called “dispatch”.  The
 applicable methods are those all of whose specializers are compatible
 with the actual arguments of the call.  Since all of the arguments must
 be compatible with the specializers, they all determine whether a method
 is applicable.  Methods that explicitly specialize more than one
 argument are called “multiple-dispatch methods”.
 
    The applicable methods are sorted into the order in which they will
 be combined.  The method whose left-most argument specializer is the
 most specific one will come first in the order.  (Specifying
 ‘:argument-precedence-order’ as part of ‘cl-defmethod’ overrides that,
 as described above.)  If the method body calls ‘cl-call-next-method’,
 the next most-specific method will run.  If there are applicable
 ‘:around’ methods, the most-specific of them will run first; it should
 call ‘cl-call-next-method’ to run any of the less specific ‘:around’
 methods.  Next, the ‘:before’ methods run in the order of their
 specificity, followed by the primary method, and lastly the ‘:after’
 methods in the reverse order of their specificity.
 
  -- Function: cl-call-next-method &rest args
      When invoked from within the lexical body of a primary or an
      ‘:around’ auxiliary method, call the next applicable method for the
      same generic function.  Normally, it is called with no arguments,
      which means to call the next applicable method with the same
      arguments that the calling method was invoked.  Otherwise, the
      specified arguments are used instead.
 
  -- Function: cl-next-method-p
      This function, when called from within the lexical body of a
      primary or an ‘:around’ auxiliary method, returns non-‘nil’ if
      there is a next method to call.