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

From: Stefan Monnier <[email-masked]>
Date: Sun, 13 Jul 2025 10:53:48 -0400

>>> 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))
[...]

>>> 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.
Think static typing vs dynamic typing (or returning nil vs signaling an
error when `function-get` is called on a cons cell, for a recent
example in Emacs).  There is no right answer in general.

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.

        Stefan