18.3.2 More complicated class precedence lists
Sometimes, more than one class precedence list is consistent with the procedure that we have outlined so far. Suppose, for example, that we had defined two additional classes, <wheeled-vehicle> and <winged-vehicle>, with the class relations illustrated in Figure 18.3.
|
Let's assume that the define class form for <aircraft> lists <winged-vehicle> before <wheeled-vehicle> in its list of direct superclasses. Now, three class precedence lists for <B707> are consistent with the procedures that we have discussed so far:
<B707>, <commercial-aircraft>, <aircraft>, <winged-vehicle>, <flying-vehicle>, <wheeled-vehicle>, <ground-vehicle>, <vehicle>, <physical-object>, <object> <B707>, <commercial-aircraft>, <aircraft>, <winged-vehicle>, <wheeled-vehicle>, <flying-vehicle>, <ground-vehicle>, <vehicle>, <physical-object>, <object> <B707>, <commercial-aircraft>, <aircraft>, <winged-vehicle>, <wheeled-vehicle>, <ground-vehicle>, <flying-vehicle>, <vehicle>, <physical-object>, <object>
In this case, Dylan uses an algorithm that tends to keep together, in the class precedence list, nonoverlapping superclass-to-subclass chains.
Look at this situation another way: The algorithm Dylan uses to construct the class precedence list in effect builds the list one class at a time, from highest to lowest precedence. The class precedence list under construction for <B707> is unambiguous from <B707> through <winged-vehicle>. At that point, Dylan could insert either <flying-vehicle> or <wheeled-vehicle> into the list. It chooses the class that has a direct subclass rightmost in the partial class precedence list that it has already constructed. In this case, <flying-vehicle> has a direct subclass <winged-vehicle>, and <wheeled-vehicle> has a direct subclass <aircraft>. Because <winged-vehicle> is rightmost in the partial list already constructed, Dylan chooses <flying-vehicle> as the next entry in the list. Once that decision has been made, the resulting class precedence list must be the first of the three possible orderings that we listed:
<B707>, <commercial-aircraft>, <aircraft>, <winged-vehicle>, <flying-vehicle>, <wheeled-vehicle>, <ground-vehicle>, <vehicle>, <physical-object>, <object>
Note that it is not always possible to compute a class precedence list. Consider the three classes defined as follows:
define class <a> (<object>) ... end class <a>; define class <b> (<a>) ... end class <b>; define class <c> (<a>, <b>) ... end class <c>;
No class precedence list is possible for class <c> in this example, because the ordering of classes <a> and <b> conflicts in the local precedence lists for classes <b> and <c>. Dylan signals an error when it tries to compute a class precedence list and finds that it cannot do so.
To examine the class precedence list for a class, we use the all-superclasses function, which returns the class and its superclasses in the same order as they appear in the class precedence list:
? all-superclasses (<B707>)
#[{class <B707>}, {class <commercial-aircraft>}, {class <aircraft>},
{class <winged-vehicle>}, {class <flying-vehicle>},
{class <wheeled-vehicle>},{class <ground-vehicle>}, {class <vehicle>}, {class <physical-object>}, {class <object>}]
The details of the algorithm that Dylan uses to construct class precedence lists are complicated, and are beyond the scope of this book. For most uncomplicated uses of simple inheritance, the most important points to remember about the class precedence list are that the list of direct superclasses in a define class form is ordered, and each direct superclass in the list takes precedence over all direct superclasses that appear later in the list. In general, if more than one superclass defines a behavior, the subclass behaves most like the first superclass in its class precedence list that defines that behavior.




