GNU bug report logs -
#78989
31.0.50; classes and methods inheritance (defclass) seq-contains-p
Previous Next
Full log
Message #20 received at 78989 <at> debbugs.gnu.org (full text, mbox):
>> FWIW, `cl--class-allparents` does not promise a general topological sort.
> It doesn't?
No, you can have classes A and B with (linearized) parents:
(A .. C .. D .. t)
(B .. D .. C .. t)
in which case inheriting from both A and B is simply not supported
because we can't create a merged linearization of the parents which
is monotonic (i.e. obeys the existing linearization in both parents).
> Then the cl-generic code won't work...
AFAIK it's good enough for most languages, so I hope it should be good
enough for us.
>> 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.
Yup: In one of the lists we have (.. widobj .. state ..) while in
another we have (.. state .. widobj ..), so this is one of those cases
that are not supported.
I do see some problems in our code:
- We should emit some warning when faced with such an
inconsistent hierarchy.
[ Note: the hierarchy is not globally inconsistent, but it becomes
inconsistent because linearization is performed
piecemeal/locally/modularly, so by the time we're faced with an
inconsistency we'd have to go back and choose different
linearizations for some of the existing classes. ]
- We should try harder to degrade gracefully in the face of inconsistent
hierarchies, e.g. avoiding multiple occurrences of the same parent or
with `t` in the middle, ...
- We should give more control to the programmer to impose a particular
choice of linearization. To mimic what CLOS does, we could use the
patch below.
With that patch Pierre could replace
(defclass loadable (loadfile interface)
(d(irectory :initarg directory)))
with
(defclass loadable (loadfile interface widobj state)
(d(irectory :initarg directory)))
to force the linearization to place `widobj` before `state`.
In turn it would require changing
(defclass interface (widobj title) ())
to
(defclass interface (title widobj) ())
or
(defclass interface (title) ())
because `widobj` is a parent of `title`.
Similarly Pierre would have to change
(defclass father (widgetlist loadable interfacelist) ())
to
(defclass father (interfacelist widgetlist loadable) ())
or
(defclass father (loadable interfacelist) ())
since `widgetlist` is a parent of `interfacelist`.
Stefan
diff --git a/lisp/emacs-lisp/cl-preloaded.el b/lisp/emacs-lisp/cl-preloaded.el
index 263a9b85225..71b4a863b30 100644
--- a/lisp/emacs-lisp/cl-preloaded.el
+++ b/lisp/emacs-lisp/cl-preloaded.el
@@ -285,8 +285,14 @@ cl--copy-slot-descriptor
(defun cl--class-allparents (class)
(cons (cl--class-name class)
- (merge-ordered-lists (mapcar #'cl--class-allparents
- (cl--class-parents class)))))
+ (let* ((parents (cl--class-parents class))
+ (aps (mapcar #'cl--class-allparents parents)))
+ (if (null (cdr aps)) ;; Single-inheritance fast-path.
+ (car aps)
+ (merge-ordered-lists
+ ;; Add the list of immediate parents, to control which
+ ;; linearization is chosen. doi:10.1145/236337.236343
+ (nconc aps (list (mapcar #'cl--class-name parents))))))))
(cl-defstruct (built-in-class
(:include cl--class)
This bug report was last modified 24 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.