cl-generic

Homepage: https://www.gnu.org/software/emacs

Author: Stefan Monnier

Summary

CLOS-style generic functions for Elisp

Commentary

This implements most of CLOS's multiple-dispatch generic functions.
To use it you need either (require 'cl-generic) or (require 'cl-lib).
The main entry points are: `cl-defgeneric' and `cl-defmethod'.

Missing elements:
- We don't support make-method, call-method, define-method-combination.
  CLOS's define-method-combination is IMO overly complicated, and it suffers
  from a significant problem: the method-combination code returns a sexp
  that needs to be `eval'uated or compiled.  IOW it requires run-time
  code generation.  Given how rarely method-combinations are used,
  I just provided a cl-generic-combine-methods generic function, to which
  people can add methods if they are really desperate for such functionality.
- In defgeneric we don't support the options:
  declare, :method-combination, :generic-function-class, :method-class.
Added elements:
- We support aliases to generic functions.
- cl-generic-generalizers.  This generic function lets you extend the kind
  of thing on which to dispatch.  There is support in this file for
  dispatch on:
  - (eql )
  - (head ) which checks that the arg is a cons with  as its head.
  - plain old types
  - type of CL structs
  eieio-core adds dispatch on:
  - class of eieio objects
  - actual class argument, using the syntax (subclass ).
- cl-generic-combine-methods (i.s.o define-method-combination and
  compute-effective-method).
- cl-generic-call-method (which replaces make-method and call-method).
- The standard method combination supports ":extra STRING" qualifiers
  which simply allows adding more methods for the same
  specializers&qualifiers.
- Methods can dispatch on the context.  For that, a method needs to specify
  context arguments, introduced by `&context' (which need to come right
  after the mandatory arguments and before anything like
  &optional/&rest/&key).  Each context argument is given as (EXP SPECIALIZER)
  which means that EXP is taken as an expression which computes some context
  and this value is then used to dispatch.
  E.g. (foo &context (major-mode (eql c-mode))) is an arglist specifying
  that this method will only be applicable when `major-mode' has value
  `c-mode'.

Efficiency considerations: overall, I've made an effort to make this fairly
efficient for the expected case (e.g. no constant redefinition of methods).
- Generic functions which do not dispatch on any argument are implemented
  optimally (just as efficient as plain old functions).
- Generic functions which only dispatch on one argument are fairly efficient
  (not a lot of room for improvement without changes to the byte-compiler,
  I think).
- Multiple dispatch is implemented rather naively.  There's an extra `apply'
  function call for every dispatch; we don't optimize each dispatch
  based on the set of candidate methods remaining; we don't optimize the
  order in which we performs the dispatches either;
  If/when this becomes a problem, we can try and optimize it.
- call-next-method could be made more efficient, but isn't too terrible.

TODO:

- A generic "filter" generalizer (e.g. could be used to cleanly add methods
  to cl-generic-combine-methods with a specializer that says it applies only
  when some particular qualifier is used).

Dependencies

Reverse dependencies