$15.1 EXAMPLES OF MULTIPLE INHERITANCE 529 class COMPOSITE FIGURE inherit FIGURE LINKED LIST [FIGURE feature end The feature clause is particularly pleasant to write.An operation on a composite figure is,in many cases,an operation on all of its constituents taken in sequence.For example,procedure display will be effected as follows in COMPOSITE FIGURE: display is Display figure by displaying all its components in turn. do from start until after loop item.display forth end end For the details see As in earlier discussions,we assume that our list classes offer traversal mechanisms based “4 ICTIVE DATA on the notion of cursor:start moves the cursor to the first element if any (otherwise afier STRUCTURES”, is immediately true),afier indicates whether the cursor is past all elements,item gives the 23.4,page774. value of the element at cursor position,and forth advances the cursor by one position. I find this scheme admirable and hope its beauty will strike you too.Almost everything is concentrated here:classes,multiple inheritance,polymorphic data structures (LINKED LIST [FIGURED),dynamic binding (the call item.display will apply the proper variant of display based on the type of each list element),recursion (note that any list element-any item-may itself be a composite figure,with no limit on the degree of nesting).To think that some people will live an entire life and never see this! Exercise E15.4. It is in fact possible to go further.Consider other COMPOSITE FIGURE features page 567. such as rotate and translate;because they all must apply the corresponding operation to every member figure in turn,their body will look very much like display.For an object- oriented designer this is cause for alert:we do not like repetition;we transform it,through encapsulation,into reuse.(This could yield a good motto.)The technique to use here is to define a deferred "iterator"class,whose instances are little machines able to iterate over a COMPOSITE FIGURE.Its effective descendants may include DISPLAY ITERATOR and so on.This is a straightforward scheme and is left to the reader as an exercise. Exercises E15.8. The technique describing composite structures through multiple inheritance,using a page 568.and E21.6.pge716. list or other container class as one of the parents,is a general design pattern,directly useful in widely different areas.Make sure to look at the exercise asking you to apply similar reasoning to the notion of submenu in a window system:a submenu is a menu,but it is also a menu entry.Another deals with composite commands in an interactive system
§15.1 EXAMPLES OF MULTIPLE INHERITANCE 529 class COMPOSITE_FIGURE inherit FIGURE LINKED_LIST [FIGURE] feature … end The feature clause is particularly pleasant to write. An operation on a composite figure is, in many cases, an operation on all of its constituents taken in sequence. For example, procedure display will be effected as follows in COMPOSITE_FIGURE: display is -- Display figure by displaying all its components in turn. do from start until after loop item ● display forth end end As in earlier discussions, we assume that our list classes offer traversal mechanisms based on the notion of cursor: start moves the cursor to the first element if any (otherwise after is immediately true), after indicates whether the cursor is past all elements, item gives the value of the element at cursor position, and forth advances the cursor by one position. I find this scheme admirable and hope its beauty will strike you too. Almost everything is concentrated here: classes, multiple inheritance, polymorphic data structures (LINKED_LIST [FIGURE]), dynamic binding (the call item ● display will apply the proper variant of display based on the type of each list element), recursion (note that any list element — any item — may itself be a composite figure, with no limit on the degree of nesting). To think that some people will live an entire life and never see this! It is in fact possible to go further. Consider other COMPOSITE_FIGURE features such as rotate and translate; because they all must apply the corresponding operation to every member figure in turn, their body will look very much like display. For an objectoriented designer this is cause for alert: we do not like repetition; we transform it, through encapsulation, into reuse. (This could yield a good motto.) The technique to use here is to define a deferred “iterator” class, whose instances are little machines able to iterate over a COMPOSITE_FIGURE. Its effective descendants may include DISPLAY_ITERATOR and so on. This is a straightforward scheme and is left to the reader as an exercise. The technique describing composite structures through multiple inheritance, using a list or other container class as one of the parents, is a general design pattern, directly useful in widely different areas. Make sure to look at the exercise asking you to apply similar reasoning to the notion of submenu in a window system: a submenu is a menu, but it is also a menu entry. Another deals with composite commands in an interactive system. For the details see “ACTIVE DATA STRUCTURES”, 23.4, page 774. Exercise E15.4, page 567. Exercises E15.8, page 568, and E21.6, page 716
530 MULTIPLE INHERITANCE $15.1 The marriage of convenience In the preceding examples the two parents played a symmetric role.This is not always the case;sometimes each parent brings a contribution of a different nature. An important application of multiple inheritance is to provide an implementation of an abstraction defined by a deferred class,using facilities provided by effective class. A marriage of STACK ARRAY convenience ARRAYED STACK Consider the implementation of stacks as arrays.Since classes are available to cover The deferredSTACK stacks as well as arrays (deferred for STACK,effective for ARRAY,both seen in earlier class appearedon chapters),the best way to implement class ARRAYED STACK,describing stacks ced implemented as arrays,is to define it as an heir to both STACK and ARRAY.This is onpage 373. conceptually right:an arrayed stack is a stack (as seen by clients)and is also an array (internally).The general form is: indexing description."Stacks implemented as arrays" class ARRAYED STACK [G]inherit STACK [G] ARRAY [G] ..A rename subclause will be added here(see page 540)... feature ..Implementation of the deferred routines of STACK in terms of ARRAY operations (see below)... end ARRAYED STACK offers the same functionality as STACK,effecting its deferred features such as full,put,count through implementations relying on array operations. Here is an outline of some typical features:firll,count and put.The condition under which a stack is full is given by
530 MULTIPLE INHERITANCE §15.1 The marriage of convenience In the preceding examples the two parents played a symmetric role. This is not always the case; sometimes each parent brings a contribution of a different nature. An important application of multiple inheritance is to provide an implementation of an abstraction defined by a deferred class, using facilities provided by effective class. Consider the implementation of stacks as arrays. Since classes are available to cover stacks as well as arrays (deferred for STACK, effective for ARRAY, both seen in earlier chapters), the best way to implement class ARRAYED_STACK, describing stacks implemented as arrays, is to define it as an heir to both STACK and ARRAY. This is conceptually right: an arrayed stack is a stack (as seen by clients) and is also an array (internally). The general form is: indexing description: "Stacks implemented as arrays" class ARRAYED_STACK [G] inherit STACK [G] ARRAY [G] … A rename subclause will be added here (see page 540) … feature … Implementation of the deferred routines of STACK in terms of ARRAY operations (see below)… end ARRAYED_STACK offers the same functionality as STACK, effecting its deferred features such as full, put, count through implementations relying on array operations. Here is an outline of some typical features: full, count and put. The condition under which a stack is full is given by A marriage of convenience ARRAYED_ STACK ∗ STACK ARRAY The deferred STACK class appeared on page 501; class ARRAY was sketched on page 373
$15.1 EXAMPLES OF MULTIPLE INHERITANCE 531 full:BOOLEAN is --Is stack representation full? do Result:=(cot=capaci) end Here capacity,inherited from class ARRAY,is the number of positions in the array. For count we need an attribute: count:INTEGER This is a case of effecting a deferred feature into an attribute.Here finally is put: put (x:G)is --Push x on top require not full do count :count I array put (x,count) end Procedure array put,inherited from ARRAY,assigns a new value to an array element given by its index. See“Using a par- The array features capacity and array_put had different names in class ARRAY:countand ent's creation proce- put.The name change is explained later in this chapter. dure".page 539. ARRAYED STACK is representative of a common kind of multiple inheritance, called the marriage ofconvenience.It is like a marriage uniting a rich family and a noble family.The bride,a deferred class,belongs to the aristocratic family of stacks:it brings prestigious functionality but no practical wealth-no implementation worth speaking of. (What good is an effective change top with a deferred put and remove?)The groom comes from a well-to-do bourgeois family,arrays,but needs some luster to match the efficiency of its implementation.The two make a perfect match. Besides providing effective implementations of routines deferred in STACK,class ARRAYED STACK may also redefine some which were not deferred.In particular,with an array representation,change top (x:G),implemented in STACK as remove followed by put (x),may be implemented more efficiently as array put(,count)) To make this redefinition valid,do not forget to announce it in the inheritance clause: class ARRAYED STACK [G]inherit STACK [G] redefine change_top end ..The rest as before... The invariant of the class might read
§15.1 EXAMPLES OF MULTIPLE INHERITANCE 531 full: BOOLEAN is -- Is stack representation full? do Result := (count = capacity) end Here capacity, inherited from class ARRAY, is the number of positions in the array. For count we need an attribute: count: INTEGER This is a case of effecting a deferred feature into an attribute. Here finally is put: put (x: G) is -- Push x on top. require not full do count := count + 1 array_put (x, count) end Procedure array_put, inherited from ARRAY, assigns a new value to an array element given by its index. The array features capacity and array_put had different names in class ARRAY: count and put. The name change is explained later in this chapter. ARRAYED_STACK is representative of a common kind of multiple inheritance, called the marriage of convenience. It is like a marriage uniting a rich family and a noble family. The bride, a deferred class, belongs to the aristocratic family of stacks: it brings prestigious functionality but no practical wealth — no implementation worth speaking of. (What good is an effective change_top with a deferred put and remove?) The groom comes from a well-to-do bourgeois family, arrays, but needs some luster to match the efficiency of its implementation. The two make a perfect match. Besides providing effective implementations of routines deferred in STACK, class ARRAYED_STACK may also redefine some which were not deferred. In particular, with an array representation, change_top (x: G), implemented in STACK as remove followed by put (x), may be implemented more efficiently as array_put (x, count) To make this redefinition valid, do not forget to announce it in the inheritance clause: class ARRAYED_STACK [G] inherit STACK [G] redefine change_top end … The rest as before … The invariant of the class might read See “Using a parent’s creation procedure”, page 539
532 MULTIPLE INHERITANCE $15.1 invariant non negative count:count>=0 bounded:count <=capacity The two parts of the assertion are of a different nature.The first expresses a property “Implementation of the abstract data type.(It was in fact already present in the parent class STACK,and so invariants”,page is redundant;it is included here for pedagogical purposes,but should not appear in a final 377. version of the class.)The second line involves capacity,that is to say the array representation:it is an implementation invariant. You might take a minute to compare ARRAYED STACK,as sketched here,with The methodological STACK2 of an earlier discussion,and see how dramatically inheritance simplifies the class. discussion is“It feels so good,but is it This comparison will be pursued in the discussion of the methodology of inheritance,which wrong?”page844. will also address some of the criticisms occasionally heard against marriage-of- STACK2 appeared convenience inheritance and,more generally,against what is sometimes called on page 350. implementation inheritance. Structure inheritance Multiple inheritance is indispensable when you want to state explicitly that a certain class possesses some properties beyond the basic abstraction that it represents. Consider for example a mechanism that makes object structures persistent (storable On STORABLE see on long-term storage).You may have to request that the lead object in a storable structure "Deep storage:a be equipped with the corresponding store and retrieve operations:in addition to its other first view ofpersis- properties such an object is"storable".In the Kemel library,as we have seen,this property tence".page 250. is captured by a class STORABLE,from which any other class can inherit.Clearly,such For a more detailed classes may have other parents as well,so this would not work without multiple inheritance. discussion ofthis This form of inheritance,from a class that describes a general structural property-often form of inheritance: “Structure inherit-- with a name that ends with-ABLE-is similar to inheritance from classes COMPARABLE amce”,page83l. and NUMER/C seen earlier in this chapter.The discussion of inheritance methodology will define it as inheritance of the structural kind. Without multiple inheritance,there would be no way to specify that a certain abstraction must possess two structural properties-numeric and storable,comparable and hashable.Selecting one of them as the parent would be like having to choose between your father and your mother. Facility inheritance Here is another typical case.Many tools need "history"facilities,enabling their users to perform such operations as: Viewing the list of recent commands. Executing again a recent command. Executing a new command defined by editing a recent one and changing a few details
532 MULTIPLE INHERITANCE §15.1 invariant non_negative_count: count >= 0 bounded: count <=capacity The two parts of the assertion are of a different nature. The first expresses a property of the abstract data type. (It was in fact already present in the parent class STACK, and so is redundant; it is included here for pedagogical purposes, but should not appear in a final version of the class.) The second line involves capacity, that is to say the array representation: it is an implementation invariant. You might take a minute to compare ARRAYED_STACK, as sketched here, with STACK2 of an earlier discussion, and see how dramatically inheritance simplifies the class. This comparison will be pursued in the discussion of the methodology of inheritance, which will also address some of the criticisms occasionally heard against marriage-ofconvenience inheritance and, more generally, against what is sometimes called implementation inheritance. Structure inheritance Multiple inheritance is indispensable when you want to state explicitly that a certain class possesses some properties beyond the basic abstraction that it represents. Consider for example a mechanism that makes object structures persistent (storable on long-term storage). You may have to request that the lead object in a storable structure be equipped with the corresponding store and retrieve operations: in addition to its other properties such an object is “storable”. In the Kernel library, as we have seen, this property is captured by a class STORABLE, from which any other class can inherit. Clearly, such classes may have other parents as well, so this would not work without multiple inheritance. This form of inheritance, from a class that describes a general structural property — often with a name that ends with -ABLE — is similar to inheritance from classes COMPARABLE and NUMERIC seen earlier in this chapter. The discussion of inheritance methodology will define it as inheritance of the structural kind. Without multiple inheritance, there would be no way to specify that a certain abstraction must possess two structural properties — numeric and storable, comparable and hashable. Selecting one of them as the parent would be like having to choose between your father and your mother. Facility inheritance Here is another typical case. Many tools need “history” facilities, enabling their users to perform such operations as: • Viewing the list of recent commands. • Executing again a recent command. • Executing a new command defined by editing a recent one and changing a few details. “Implementation invariants”, page 377. The methodological discussion is “It feels so good, but is it wrong?”, page 844. STACK2 appeared on page 350. On STORABLE see “Deep storage: a first view of persistence”, page 250. For a more detailed discussion of this form of inheritance: “Structure inheritance”, page 831
$15.1 EXAMPLES OF MULTIPLE INHERITANCE 533 Undoing the effect of the last command not yet undone Such a mechanism makes any interactive tool nicer to use.But it is a chore to write. As a result,only a few tools(such as certain"shells"under Unix and Windows)support it, often partially.Yet the general techniques are tool-independent.They can be encapsulated in a class,from which a session-control class for any tool can then inherit.(A solution based on the client relation may be possible,but is less attractive.)Once again,without multiple inheritance such an inheritance link would conflict with other possible parents. A similar case is that of a class TEST encapsulating a number of mechanisms useful for testing a class:getting and storing user input,printing and storing output,comparing with expected values,recording all the results,comparing with earlier test runs(regression testing),managing the testing process.Although a client-based solution may be preferable in some cases,it is convenient to have the possibility,for testing a class X,of defining a class X TEST that inherits from X and from TEST. In later chapters we will encounter other cases of such facility inheritance,whereby a class F encapsulates a set of related facilities,such as constants or routines from a mathematical library,which any class can then obtain by inheriting from F. See chapter 24. Although the use of inheritance in such cases is sometimes viewed with suspicion,it is in fact a perfectly legitimate application of the concept.It does differ in one respect from the other examples of multiple inheritance reviewed in this chapter:in the cases just reviewed,we could achieve our goals,albeit less conveniently,with a client rather than inheritance link. Buttonholes Here is a case in which,as in earlier ones,multiple inheritance is indispensable.It is similar in spirit to“company planes'”,“sleeping cars'”and other examples of the combination-of-abstractions type encountered earlier.Rather than using concepts from some external model,however,this one deals with genuine software abstractions.The reason why it has been moved to the end of this review of multiple inheritance examples is that understanding it requires a little background preparation. See chapter 36. Like other graphical applications,many tools of the development environment presented in the last chapter offer "buttons",on which you can click to trigger certain operations.They also use a"pick and throw"mechanism (a variation on traditional"drag- and-drop"),through which you can select a visual object,causing the mouse cursor to change into a "pebble"that indicates the type of the object,and bring it to a hole of a matching shape.You can "throw"the pebble into the hole by right-clicking;this causes some operation to occur.For example,a Class Tool,which you use to explore the properties of a class in the development environment,has a"class hole"into which you can drag-and-drop a class pebble;this causes the tool to retarget itselfto the selected class
§15.1 EXAMPLES OF MULTIPLE INHERITANCE 533 • Undoing the effect of the last command not yet undone Such a mechanism makes any interactive tool nicer to use. But it is a chore to write. As a result, only a few tools (such as certain “shells” under Unix and Windows) support it, often partially. Yet the general techniques are tool-independent. They can be encapsulated in a class, from which a session-control class for any tool can then inherit. (A solution based on the client relation may be possible, but is less attractive.) Once again, without multiple inheritance such an inheritance link would conflict with other possible parents. A similar case is that of a class TEST encapsulating a number of mechanisms useful for testing a class: getting and storing user input, printing and storing output, comparing with expected values, recording all the results, comparing with earlier test runs (regression testing), managing the testing process. Although a client-based solution may be preferable in some cases, it is convenient to have the possibility, for testing a class X, of defining a class X_TEST that inherits from X and from TEST. In later chapters we will encounter other cases of such facility inheritance, whereby a class F encapsulates a set of related facilities, such as constants or routines from a mathematical library, which any class can then obtain by inheriting from F. Although the use of inheritance in such cases is sometimes viewed with suspicion, it is in fact a perfectly legitimate application of the concept. It does differ in one respect from the other examples of multiple inheritance reviewed in this chapter: in the cases just reviewed, we could achieve our goals, albeit less conveniently, with a client rather than inheritance link. Buttonholes Here is a case in which, as in earlier ones, multiple inheritance is indispensable. It is similar in spirit to “company planes”, “sleeping cars” and other examples of the combination-of-abstractions type encountered earlier. Rather than using concepts from some external model, however, this one deals with genuine software abstractions. The reason why it has been moved to the end of this review of multiple inheritance examples is that understanding it requires a little background preparation. Like other graphical applications, many tools of the development environment presented in the last chapter offer “buttons”, on which you can click to trigger certain operations. They also use a “pick and throw” mechanism (a variation on traditional “dragand-drop”), through which you can select a visual object, causing the mouse cursor to change into a “pebble” that indicates the type of the object, and bring it to a hole of a matching shape. You can “throw” the pebble into the hole by right-clicking; this causes some operation to occur. For example, a Class Tool, which you use to explore the properties of a class in the development environment, has a “class hole” into which you can drag-and-drop a class pebble; this causes the tool to retarget itself to the selected class. See chapter 24. See chapter 36