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

From: Pip Cet <[email-masked]>
Date: Sun, 13 Jul 2025 15:25:00 +0000

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

>>>> I'm convinced both of your patches will still produce
>>>> topologically inconsistent orderings.
>>> Not without emitting a warning along the way.
>> I'm very confused here.  Can you make sure you sent the right patch?
>> Or point out where the last patch emits a warning?  I just don't see any
>> code to do so.
>
> [...]
> +	    (setq next (funcall (or error-function
> +	                            (lambda (remaining-lists)
> +                                      (message "Inconsistent hierarchy: %S"
> +                                               remaining-lists)
> +                                      (caar remaining-lists)))
> +	                        tail))
> [...]

Sorry for the noise. Clearly, I'm not in a state to read patches right
now, though I'm not sure why.

Warning about it (even with message) is fine, I guess. I still prefer
"order of inheritance is mostly irrelevant" semantics, but maybe that is
more appropriate for statically-typed languages (like C++).

>>>> That is because the information necessary to figure out how to break
>>>> an artificial "cycle" is lost the second we stop considering the
>>>> inheritance graph and limit ourselves to previously-linearized
>>>> ancestor lists.
>>> Indeed.  That's a choice between losing monotonicity and suffering from
>>> artificial-cycles.  You can't avoid both.  But years of experience in
>>> other languages told us that it's easier for programmers to deal with
>>> artificial cycles than with loss of monotonicity.
>> I'm baffled by that, but I'll take your word for it.
>
> There's often/always a tension between detecting (apparent) errors
> early, at the cost of disallowing valid use-cases, vs postponing error
> signaling to the moment you can't avoid it any more.

I agree, of course. I don't really know how hard it would be to detect
overlapping-but-unordered cl-defmethod calls, but as long as we don't,
you've convinced me that monotonicity is the right thing to do.

However, in this case, all fields of the Venn diagram are nonempty: the
semantics I'd prefer allow use cases monotonicity doesn't allow, and
assuming monotonicity allows use cases that I'd prefer produce, at
least, warnings.

> In the present case, I think the reason why this is the preferred
> option, is that loss of monotonicity leads to code being run in
> a different order, which tends to lead to errors being detected further
> away (sometimes very far), making it harder to trace the problem back to
> its origin.  Another reason is likely also that such conflicts are
> fairly rare and can always be solved with a few tweaks to the code, so
> the downside is fairly minor.

Just to be clear, what I would prefer is:

1. cl-defmethods that overlap but aren't ordered by the inheritance
graph (rather than by the order of inheritance) cause a warning.

2. if there is a monotonic order, cl--class-allparents uses it.

3. if there isn't, and there is a topologically correct order that
violates monotonicity, cl--class-allparents returns that instead.

Doing (1) even at definition time is probably expensive, and doing it at
invocation time, I expect, prohibitively so.  (2) is existing behavior,
and (3) simply requires us to add an error handler which uses the "best"
topological order.

All that said, while I think (3) is the expected behavior for people
expecting C++-like semantics, I see why you would want to warn about it.

Sorry again,
Pip