The defclass
form for a class provides a total ordering
on that class and its direct superclasses. This ordering is
called the local precedence order. It is an ordered list of the
class and its direct superclasses. The
class precedence list for a class C is a total ordering on
C and its superclasses that is consistent with the
local precedence orders for each of C and its superclasses.
A class precedes its direct superclasses,
and a direct superclass precedes all other
direct superclasses specified to its right
in the superclasses list of the defclass
form.
For every class C, define
RC={(C,C1),(C1,C2),...,(Cn-1,Cn)}where C1,...,Cn are the direct superclasses of C in the order in which they are mentioned in the
defclass
form. These ordered pairs
generate the total ordering on the class C and its direct
superclasses.
Let SC be the set of C and its superclasses. Let R be
R=⋃c∈ SCRc.
The set R might or might not generate a partial ordering, depending on whether the Rc, c∈ SC, are consistent; it is assumed that they are consistent and that R generates a partial ordering. When the Rc are not consistent, it is said that R is inconsistent.
To compute the class precedence list for C, topologically sort the elements of SC with respect to the partial ordering generated by R. When the topological sort must select a class from a set of two or more classes, none of which are preceded by other classes with respect to R, the class selected is chosen deterministically, as described below.
If R is inconsistent, an error is signaled.
Topological sorting proceeds by finding a class C in SC such that no other class precedes that element according to the elements in R. The class C is placed first in the result. Remove C from SC, and remove all pairs of the form (C,D), D∈ SC, from R. Repeat the process, adding classes with no predecessors to the end of the result. Stop when no element can be found that has no predecessor.
If SC is not empty and the process has stopped, the set R is inconsistent. If every class in the finite set of classes is preceded by another, then R contains a loop. That is, there is a chain of classes C1,...,Cn such that Ci precedes Ci+1, 1≤ i<n, and Cn precedes C1.
Sometimes there are several classes from SC with no predecessors. In this case select the one that has a direct subclass rightmost in the class precedence list computed so far. (If there is no such candidate class, R does not generate a partial ordering—the Rc, c∈ SC, are inconsistent.)
In more precise terms, let {N1,...,Nm}, m≥ 2, be the classes from SC with no predecessors. Let (C1... Cn), n≥ 1, be the class precedence list constructed so far. C1 is the most specific class, and Cn is the least specific. Let 1≤ j≤ n be the largest number such that there exists an i where 1≤ i≤ m and Ni
is a direct superclass of Cj; Ni is placed next.
The effect of this rule for selecting from a set of classes with no predecessors is that the classes in a simple superclass chain are adjacent in the class precedence list and that classes in each relatively separated subgraph are adjacent in the class precedence list. For example, let T1 and T2 be subgraphs whose only element in common is the class J. Suppose that no superclass of J appears in either T1 or T2, and that J is in the superclass chain of every class in both T1 and T2. Let C1 be the bottom of T1; and let C2 be the bottom of T2. Suppose C is a class whose direct superclasses are C1 and C2 in that order, then the class precedence list for C starts with C and is followed by all classes in T1 except J. All the classes of T2 are next. The class J and its superclasses appear last.
This example determines a class precedence list for the
class pie
. The following classes are defined:
(defclass pie (apple cinnamon) ()) (defclass apple (fruit) ()) (defclass cinnamon (spice) ()) (defclass fruit (food) ()) (defclass spice (food) ()) (defclass food () ())
The set Spie = {pie, apple, cinnamon, fruit, spice, food,
standard-object, t
}. The set R = {(pie, apple),
(apple, cinnamon), (apple, fruit), (cinnamon, spice),
(fruit, food), (spice, food), (food, standard-object), (standard-object,
t)
}.
The class pie
is not preceded by anything, so it comes first;
the result so far is (pie)
. Remove pie
from S and pairs
mentioning pie
from R to get S = {apple, cinnamon,
fruit, spice, food, standard-object, t
} and R = {(apple, cinnamon), (apple, fruit), (cinnamon, spice), (fruit,
food), (spice, food), (food, standard-object),
(standard-object, t)
}.
The class apple
is not preceded by anything, so it is next; the
result is (pie apple)
. Removing apple
and the relevant
pairs results in S = {cinnamon, fruit, spice, food,
standard-object, t
} and R = {(cinnamon, spice),
(fruit, food), (spice, food), (food, standard-object),
(standard-object, t)
}.
The classes cinnamon
and fruit
are not preceded by
anything, so the one with a direct subclass rightmost in the
class precedence list computed so far goes next. The class apple
is a
direct subclass of fruit
, and the class pie
is a direct
subclass of cinnamon
. Because apple
appears to the right
of pie
in the class precedence list,
fruit
goes next, and the
result so far is (pie apple fruit)
. S = {cinnamon,
spice, food, standard-object, t
}; R = {(cinnamon,
spice), (spice, food), (food, standard-object),
(standard-object, t)
}.
The class cinnamon
is next, giving the result so far as (pie apple fruit cinnamon)
. At this point S = {spice,
food, standard-object, t
}; R = {(spice, food), (food,
standard-object), (standard-object, t)
}.
The classes spice
, food
, standard-object
, and
t
are added in that order, and the class precedence list
is (pie apple fruit cinnamon spice food standard-object t)
.
It is possible to write a set of class definitions that cannot be ordered. For example:
(defclass new-class (fruit apple) ()) (defclass apple (fruit) ())
The class fruit
must precede apple
because the local ordering of superclasses must be preserved.
The class apple
must precede fruit
because a class always precedes its own superclasses.
When this situation occurs, an error is signaled, as happens here
when the system tries to compute the class precedence list
of new-class
.
The following might appear to be a conflicting set of definitions:
(defclass pie (apple cinnamon) ()) (defclass pastry (cinnamon apple) ()) (defclass apple () ()) (defclass cinnamon () ())
The class precedence list for pie
is
(pie apple cinnamon standard-object t)
.
The class precedence list for pastry
is
(pastry cinnamon apple standard-object t)
.
It is not a problem for apple
to precede cinnamon
in the
ordering of the superclasses of pie
but not in the ordering for
pastry
. However, it is not possible to build a new class that
has both pie
and pastry
as superclasses.