Function: cl--derived-type-specializers

cl--derived-type-specializers is a byte-compiled function defined in cl-extra.el.gz.

Signature

(cl--derived-type-specializers OBJECT TYPES)

Documentation

Return the list of specializers for OBJECT, derived from TYPES.

Return an unique (eq) list of atomic types OBJECT belongs to, ordered from the most specific type to the most general. TYPES is a list of types that OBJECT can potentially belong to.

Source Code

;; Defined in /usr/src/emacs/lisp/emacs-lisp/cl-extra.el.gz
;; The usual dispatch is
;;
;;   (lambda (arg &rest args)
;;     (let ((f (gethash (cl-typeof arg) precomputed-methods-table)))
;;       (if f
;;           (apply f arg args)
;;         ;; Slow case when encountering a new type
;;         ...)))
;;
;; where often the most expensive part is `&rest' (which has to
;; allocate a list for those remaining arguments),
;;
;; So we're talking about replacing
;;
;;   &rest + cl-type-of + gethash + if + apply
;;
;; with a function that loops over N types, calling `cl-typep' on each
;; one of them (`cl-typep' itself being a recursive function that
;; basically interprets the type language).  This is going to slow
;; down dispatch very significantly for those generic functions that
;; have a method that dispatches on a derived type, compared to
;; those that don't.
;;
;; As a simple optimization, the method dispatch tests only those
;; derived types which have been used as a specialize in a method.
;;
;; A possible further improvement:
;;
;; - based on the PARENTS declaration, create a map from builtin-type
;;   to the set of cl-types that have that builtin-type among their
;;   parents.  That presumes some PARENTS include some builtin-types,
;;   obviously otherwise the map will be trivial with all cl-types
;;   associated with the `t' "dummy parent".  [ We could even go crazy
;;   and try and guess PARENTS when not provided, by analyzing the
;;   type's definition. ]
;; - in `cl--derived-type-specializers' start by calling `cl-type-of',
;;   then use the map to find which cl-types may need to be checked.
;;
(defun cl--derived-type-specializers (object types)
  "Return the list of specializers for OBJECT, derived from TYPES.
Return an unique (eq) list of atomic types OBJECT belongs to, ordered
from the most specific type to the most general.
TYPES is a list of types that OBJECT can potentially belong to."
  ;; This function is speed critical for the dispatch on CL's derived types.
  ;; Currently TYPES is just the set of types we're interested in.
  ;; TODO: We could speed this up by replacing TYPES with anything that can
  ;; be precomputed from it.
  (let* ((found (list (cl-type-of object))))
    ;; Build a list of all types OBJECT belongs to.
    (dolist (type types)
      ;; If OBJECT is of type, add type to the matching list.
      (if (funcall (get type 'cl-deftype-satisfies) object)
          (push type found)))
    ;; This memoization has two purposes:
    ;; - Speed up computation.
    ;; - Make sure we always return the same (eq) object, so that the
    ;;   method dispatch's own caching works as it should.
    (with-memoization (gethash found cl--derived-type-specializers-memo)
      ;; Compute an ordered list of types from the DAG.
      (merge-ordered-lists
       (mapcar (lambda (type)
                 (cl--class-allparents (cl--find-class type)))
               found)))))