GNU bug report logs -
#77725
31.0.50; Add support for types accepted by `cl-typep' to cl-generic?
Previous Next
To reply to this bug, email your comments to 77725 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77725
; Package
emacs
.
(Fri, 11 Apr 2025 07:16:02 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
David Ponce <da_vid <at> orange.fr>
:
New bug report received and forwarded. Copy sent to
bug-gnu-emacs <at> gnu.org
.
(Fri, 11 Apr 2025 07:16:02 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Hello
In the cl-generic library, the implementation of the
`cl-generic-generalizers' "typeof" method, used to dispatch
"normal types", mentions in a FIXME on line 1367: "Add support for
other "types" accepted by `cl-typep' such as `character', `face',
`keyword', ...?".
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
(my-add-face "text" 'bold)
=> #("text" 0 4 (face bold))
(my-add-face "text" 'bad-face)
=> No applicable method: add-face, "text", bad-face
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.
My library is relatively concise and adopts a design similar to that
used for built-in types. The new types (which I call "gtypes") are
instances of the structure `gtype-class', derived from `cl--class',
just as built-in types are instances of the structure `built-in-class'
also derived from `cl--class'. gtypes thus benefits from the existing
infrastructure used for other types. I also chose to have a separate
"generalizer" for gtypes. I'm not sure if it would be desirable to
extend the existing generalizer "typof" to support such types.
I would therefore be interested in hearing more expert opinions on
my implementation and whether it could help add this functionality to
cl-generic, if it makes sense.
Thank you for your time.
[gtype.el (text/x-emacs-lisp, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77725
; Package
emacs
.
(Fri, 11 Apr 2025 08:38:01 GMT)
Full text and
rfc822 format available.
Message #8 received at 77725 <at> debbugs.gnu.org (full text, mbox):
> Date: Fri, 11 Apr 2025 09:14:41 +0200
> From: David Ponce via "Bug reports for GNU Emacs,
> the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
> In the cl-generic library, the implementation of the
> `cl-generic-generalizers' "typeof" method, used to dispatch
> "normal types", mentions in a FIXME on line 1367: "Add support for
> other "types" accepted by `cl-typep' such as `character', `face',
> `keyword', ...?".
>
> 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
>
> (my-add-face "text" 'bold)
> => #("text" 0 4 (face bold))
>
> (my-add-face "text" 'bad-face)
> => No applicable method: add-face, "text", bad-face
>
> 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.
>
> My library is relatively concise and adopts a design similar to that
> used for built-in types. The new types (which I call "gtypes") are
> instances of the structure `gtype-class', derived from `cl--class',
> just as built-in types are instances of the structure `built-in-class'
> also derived from `cl--class'. gtypes thus benefits from the existing
> infrastructure used for other types. I also chose to have a separate
> "generalizer" for gtypes. I'm not sure if it would be desirable to
> extend the existing generalizer "typof" to support such types.
>
> I would therefore be interested in hearing more expert opinions on
> my implementation and whether it could help add this functionality to
> cl-generic, if it makes sense.
Thanks, adding Stefan to the discussion.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77725
; Package
emacs
.
(Fri, 11 Apr 2025 13:42:02 GMT)
Full text and
rfc822 format available.
Message #11 received at 77725 <at> debbugs.gnu.org (full text, mbox):
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
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77725
; Package
emacs
.
(Fri, 11 Apr 2025 15:05:02 GMT)
Full text and
rfc822 format available.
Message #14 received at 77725 <at> debbugs.gnu.org (full text, mbox):
On 2025-04-11 15:41, Stefan Monnier wrote:
> 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
>
Hi Stefan,
Thank you very much for your feedback!
Your remarks make sense, for sure.
Does this mean that for a `cl-deftype'-like generalizer to work
correctly, it must be part of the "typof" generalizer?
In other words, that a function like `gtype-of' should fall back to
`cl-type-of' when there is no corresponding gtype for an object?
Or am I missing something? --- Sorry, I only started studying
cl-generic relatively recently, and I probably don't understand
all its intricacies ;-)
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77725
; Package
emacs
.
(Fri, 11 Apr 2025 16:27:01 GMT)
Full text and
rfc822 format available.
Message #17 received at 77725 <at> debbugs.gnu.org (full text, mbox):
> Does this mean that for a `cl-deftype'-like generalizer to work
> correctly, it must be part of the "typof" generalizer?
No, but it needs to be either always more precise or always less precise
than `type-of`.
IOW, either:
(eql (gtypeof-generalizer A) (gtypeof-generalizer B))
IMPLIES ((eql (gtypeof-generalizer A) nil)
OR (eql (cl-type-of A) (cl-type-of B)))
or the reverse. That's a current limitation in the cl-generic system.
One way to solve this is to use a generalizer that returns either nil or
a pair containing both the `gtype-of` and the `cl-type-of`, so it's
trivially always more precise than `cl-type-of`. But beware: these
things are compared with `eql` so you need to "uniquify" them with
a sort of hashconsing scheme.
BTW if you do
(defgtype cons-car-foo nil ()
"A cons with a `foo' car."
`(satisfies ,(lambda (x) (eq (car-safe x) 'foo))))
(defgtype cons-cdr-foo nil ()
"A cons with a `foo' cdr."
`(satisfies ,(lambda (x) (eq (cdr-safe x) 'foo))))
what's the `(gtype-of '(foo . foo))` ?
> Or am I missing something? --- Sorry, I only started studying
> cl-generic relatively recently, and I probably don't understand
> all its intricacies ;-)
Yeah, it's unsatisfactorily intricate, indeed. It's designed first and
foremost to keep the dispatch "simple and reasonable fast", at the cost
of making `cl-generic-define-generalizer` a very sharp tool. 🙂
I have recently been thinking about how to make it more reliable (which
would also make it more flexible/powerful, allowing the definition of
both `and` and `or` specializers). I have some vague idea, but there's
no code at all yet, and it might come with some non-trivial tradeoffs
(e.g. preloading the byte-compiler).
Stefan
This bug report was last modified 1 day ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.