Subject: bug#78989: 31.0.50; classes and methods inheritance (defclass) seq-contains-p

From: Pip Cet <[email-masked]>
Date: Fri, 11 Jul 2025 16:02:24 +0000

"Stefan Monnier" <[email-masked]> writes:

> Pip Cet [2025-07-11 13:43:30] wrote:
>
>> "Eli Zaretskii" <[email-masked]> writes:
>>
>>>> From: "Pierre L. Nageoire" <[email-masked]>
>>>> Date: Thu, 10 Jul 2025 10:31:50 +0200
>>>>
>>>> Code below has a different behavior in the current emacs version
>>>> (referenced in this mail) and in the last git pull one (one day ago)
>>>> that I will name new!
>>>>
>>>>
>>>> In current version it produces the expected message
>>>> "Son does not contain dummy"
>>>>
>>>> but in new one it trigger the error also included below.
>>>>
>>>> Please excuse me for the complicated code but it was very tricky to find
>>>> a minimal class tree structure that triggers the error.
>>>>
>>>> I suspect that problem comes from the method lookup through the
>>>> inheritance class tree. This schedule has maybe been modified recently ;
>>>> and it is perhaps not a bug but simply changes in inheritance scope.
>>>>
>>>> I know that that whole stuff is work in progress and that things may
>>>> change from time to time.
>>>>
>>>> Anywa it looks me strange that the reimplemented method `seq-contains-p'
>>>> cannot be reached from son while it can be from father. From son it
>>>> fallback on the method for sequence as shown in the error report.
>>>>
>>>> Sory that mother seems to be responsbile for that !
>>>
>>> Thanks, I added the usual suspects to this discussion.
>>
>> I think the bug is in cl--class-allparents, which incorrectly assumes
>> topological sorting can be done recursively, but it's hidden by another
>> problem:
>
> FWIW, `cl--class-allparents` does not promise a general topological sort.

It doesn't?  Then the cl-generic code won't work...

>> Consider '((a b) (a c) (c b)):
>
> This would be an invalid input: class `a` cannot have two different
> lists of parents.

I was talking about the topological sort problem.  The problem is we
establish a sort order between different parent classes, and that causes
a conflict.

>> In our case, the incorrect partially-sorted return value of
>> cl--class-allparents has t appear in the list before `baselist` does, so
>> we end up trying to use the wrong method: we incorrectly assume that t
>> is a more specific type than `baselist`.
>
> Good spotting.  I traced this further to:
>
> 1 -> (merge-ordered-lists ((widgetlist widobj baselist state sortable
> eieio-default-superclass record atom t) (loadable loadfile loader
> eieio-persistent state interface title widobj abstitle
> eieio-default-superclass record atom t) (interfacelist widgetlist
> interface title widobj baselist state sortable abstitle
> eieio-default-superclass record atom t)))
> 1 <- merge-ordered-lists: (loadable loadfile loader eieio-persistent
> interfacelist widgetlist widobj baselist state interface title widobj
> baselist state sortable abstitle eieio-default-superclass record atom
> t)
>
> where we see that `baselist` (and several others as well) appears twice in the output.

which is the behavior of merge-ordered-lists when given a non-fatal (or
no) error-function.

Pip