Subject: bug#77725: 31.0.50; Add support for types accepted by `cl-typep' to cl-generic?

From: Stefan Monnier <[email-masked]>
Date: Fri, 11 Apr 2025 09:41:40 -0400

Hi David,

>> As part of some other works, I created the attached "gtype" library,
>> which complements `cl-deftype' so that such defined types are also
>> recognized as argument types for dispatching generic function methods.
>> Here is a quick example of use:
>> 
>> (defgtype face nil ()
>>    "A face type."
>>    '(satisfies facep))
>> 
>> (gtype-of 'default)
>> => face
>> (cl-type-of 'default)
>> => symbol
>> 
>> (cl-defmethod my-add-face ((text string) (face face))
>>    (propertize text 'face face))
>> => my-add-face

Nice.

>> I've been using this library successfully in some of my code, and was
>> wondering if it could help add this functionality to Emacs.  My goal
>> is not to include this library, but to use it as a starting point for
>> further reflection on this subject.

The problem with adding new generalizers is to make sure they interact
correctly with others.  If you allow `satisfies` kind of definitions,
then it's easy to end up with situations where one of your new types is
neither a subtype (aka sub-specializer) nor a supertype
(super-specializer) of an existing type (specializer).

Let's take `function` defined as `(satisfies functionp)` is an example.

    (functionp '(lambda () 1))
    => t
    (type-of '(lambda a))
    => cons

this suggests (satisfies functionp) should be a subtype of `cons`, but
that is clearly wrong because

    (functionp (lambda () 1))
    => t
    (consp (lambda () 1))
    => nil

The type-dispatch code wants *one* value (generalizer) to lookup the
hash-table where it will find the corresponding effective method.
That one value should be "the most specific" generalizer among the
generalizers currently used for that generic function.

Now a `gtype-of` called `g-function` built from `(satisfies functionp)`
will be sometimes more specific and sometimes less specific than
`type-of`, so there is no correct PRIORITY to indicate to
`cl-generic-define-generalizer`: we'll end up with dispatch errors if
a generic function has a method for both `g-function` and for `cons`.

        Stefan