24 Using inheritance well mingall the thical detailsfndchisd part C,does not automatically mean that we have fully grasped the methodological consequences.Of all issues in object technology,none causes as much discussion as the question of when and how to use inheritance;sweeping opinions abound,for example on Internet discussion groups,but the literature is relatively poor in precise and useful advice In this chapter we will probe further into the meaning of inheritance,not for the sake of theory,but to make sure we use it best to benefit our software development projects. We will in particular try to understand how inheritance differs from the other inter-module relation in object-oriented system structures,its sister and rival,the client relation:when to use one,when to use the other,when both choices are acceptable.Once we have set the basic criteria for using inheritance-identifying along the way the typical cases in which it is wrong to use it-we will be able to devise a classification of the various legitimate uses,some widely accepted (subtype inheritance),others,such as implementation or facility inheritance,more controversial.Along the way we will try to learn a little from the experience in taxonomy,or systematics,gained from older scientific disciplines. 24.1 HOW NOT TO USE INHERITANCE To arrive at a methodological principle,it is often useful-as illustrated by so many other discussions in this book-to study first how not to do things.Understanding a bad idea helps find good ones,which we might otherwise miss.In too constantly warm a climate,a pear tree will not flower,it needs the jolt of Winter frost to attain full bloom in the Spring Extracts from "Soft- Here the jolt is obligingly provided by a widely successful undergraduate textbook, ware Engineering” used throughout the world to teach software engineering to probably more computing by lan Sommerville, Fscience students than any other.Already in its fourth edition,it introduced some elements of ison-Wesley,1993.object orientation,including a discussion of multiple inheritance.Here is the beginning: Multiple inheritance allows several objects to act as base objects and is supported in object-oriented languages such as [the notation of the present book][M 1988]. The bibliographic reference is to the first edition of the present book.Apart from the unfortunate use of"objects"for classes,this is an auspicious start.The extract continues: The characteristics of several different object classes (classes,good!)
24 Using inheritance well Learning all the technical details of inheritance and related mechanisms, as we did in part C, does not automatically mean that we have fully grasped the methodological consequences. Of all issues in object technology, none causes as much discussion as the question of when and how to use inheritance; sweeping opinions abound, for example on Internet discussion groups, but the literature is relatively poor in precise and useful advice. In this chapter we will probe further into the meaning of inheritance, not for the sake of theory, but to make sure we use it best to benefit our software development projects. We will in particular try to understand how inheritance differs from the other inter-module relation in object-oriented system structures, its sister and rival, the client relation: when to use one, when to use the other, when both choices are acceptable. Once we have set the basic criteria for using inheritance — identifying along the way the typical cases in which it is wrong to use it — we will be able to devise a classification of the various legitimate uses, some widely accepted (subtype inheritance), others, such as implementation or facility inheritance, more controversial. Along the way we will try to learn a little from the experience in taxonomy, or systematics, gained from older scientific disciplines. 24.1 HOW NOT TO USE INHERITANCE To arrive at a methodological principle, it is often useful — as illustrated by so many other discussions in this book — to study first how not to do things. Understanding a bad idea helps find good ones, which we might otherwise miss. In too constantly warm a climate, a pear tree will not flower; it needs the jolt of Winter frost to attain full bloom in the Spring. Here the jolt is obligingly provided by a widely successful undergraduate textbook, used throughout the world to teach software engineering to probably more computing science students than any other. Already in its fourth edition, it introduced some elements of object orientation, including a discussion of multiple inheritance. Here is the beginning: Multiple inheritance allows several objects to act as base objects and is supported in object-oriented languages such as [the notation of the present book] [M 1988]. The bibliographic reference is to the first edition of the present book. Apart from the unfortunate use of “objects” for classes, this is an auspicious start. The extract continues: The characteristics of several different object classes (classes, good!) Extracts from “Software Engineering” by Ian Sommerville, Fourth edition, Addison-Wesley, 1993
810 USING INHERITANCE PROPERLY $24.1 can be combined to make up a new object (no luck).Then comes the example of multiple inheritance: For example,say we have an object class CAR which encapsulates information about cars and an object class PERSON which encapsulates information about people.We could use both of these to define (will our worst fears come out true?) a new object class CAR-OWNER which combines the attributes of CAR and PERSON. (They have.We are invited to consider that every CAR-OWNER object may be viewed as not only a person but also a car.To anyone who has studied inheritance even at an elementary level,this will be a surprise. As you will undoubtedly have figured out,the relation to use in the second case was client,not inheritance:a car owner is a person,but has a car.In pictures: A proper model PERSON Inheritance Client CAR OWNER CAR In formal words: class CAR OWNER inherit PERSON feature my car:CAR end -class CAR OWNER In the cited text,both links use the inheritance relation.The most interesting twist actually comes a little later in the discussion,when the author advises his reader to treat inheritance with caution: Adaptation through inheritance tends to lead to extra functionality being inherited,which can make components inefficient and bulky. Bulky indeed;think of the poor car owner,loaded with his roof,engine and carburetor,not to mention four wheels plus a spare.This view might have been influenced by one of the picturesque phrases of Australian slang,about a car owner who does look as if he also is his car:
810 USING INHERITANCE PROPERLY §24.1 can be combined to make up a new object. (no luck). Then comes the example of multiple inheritance: For example, say we have an object class CAR which encapsulates information about cars and an object class PERSON which encapsulates information about people. We could use both of these to define (will our worst fears come out true?) a new object class CAR-OWNER which combines the attributes of CAR and PERSON. (They have.) We are invited to consider that every CAR-OWNER object may be viewed as not only a person but also a car. To anyone who has studied inheritance even at an elementary level, this will be a surprise. As you will undoubtedly have figured out, the relation to use in the second case was client, not inheritance: a car owner is a person, but has a car. In pictures: In formal words: class CAR_OWNER inherit PERSON feature my_car: CAR … end -- class CAR_OWNER In the cited text, both links use the inheritance relation. The most interesting twist actually comes a little later in the discussion, when the author advises his reader to treat inheritance with caution: Adaptation through inheritance tends to lead to extra functionality being inherited, which can make components inefficient and bulky. Bulky indeed; think of the poor car owner, loaded with his roof, engine and carburetor, not to mention four wheels plus a spare. This view might have been influenced by one of the picturesque phrases of Australian slang, about a car owner who does look as if he also is his car: A proper model PERSON CAR_ OWNER CAR Inheritance Client
$24.1 HOW NOT TO USE INHERITANCE 811 “He has ahead like an Austin Mini with the doors open”. Cartoon by Geoff Hocking;from The Dictionary of Aussie Slang,The Five Mile Press, Melbourne, Australia,reprinted with permission. Inheritance is a non-trivial concept,so we can forgive the author of this extract on the grounds that he was perhaps a little far from his home turf.But the example has an important practical benefit apart from helping us feel smarter:it reminds us of the basic rule on inheritance. “ls-a”rule of inheritance Do not make a class B inherit from a class 4 unless you can somehow make the argument that one can view every instance of B also as an instance of4. In other words,we must be able to convince someone-if only ourselves to start with一that“every B is an A”(hence the name:“is-a"). In spite of what you may think at first,this is a loose rule,not a strict one.Here is why: Note the phrase"can somehow make the argument".This is voluntarily vague:we do not require a proof that every B is an A.Many cases will leave room for discussion.Is it true that"Every savings account is a checking account"?There is no absolute answer;depending on the bank's policies and your analysis of the properties of the various kinds of account,you may decide to make class S4IINGS ACCOUNT an heir to BANK ACCOUNT,or put it elsewhere in the inheritance structure,getting some help from the other criteria discussed in this chapter. Reasonable people might still disagree on the result.But for this to be the case the "is-a"argument must be sustainable.Once again our counter-example helps:the argument that a CAR OWNER "is-a"CAR is not sustainable. Our view of what"is-a"means will be particularly liberal.It will not,for example, disallow implementation inheritance-a form of inheritance that many people view with suspicion一as long as the“is-a”argument can reasonably be made
§24.1 HOW NOT TO USE INHERITANCE 811 Inheritance is a non-trivial concept, so we can forgive the author of this extract on the grounds that he was perhaps a little far from his home turf. But the example has an important practical benefit apart from helping us feel smarter: it reminds us of the basic rule on inheritance. In other words, we must be able to convince someone — if only ourselves to start with — that “every B is an A” (hence the name: “is-a”). In spite of what you may think at first, this is a loose rule, not a strict one. Here is why: • Note the phrase ‘‘can somehow make the argument”. This is voluntarily vague: we do not require a proof that every B is an A. Many cases will leave room for discussion. Is it true that “Every savings account is a checking account”? There is no absolute answer; depending on the bank’s policies and your analysis of the properties of the various kinds of account, you may decide to make class SAVINGS_ ACCOUNT an heir to BANK_ACCOUNT, or put it elsewhere in the inheritance structure, getting some help from the other criteria discussed in this chapter. Reasonable people might still disagree on the result. But for this to be the case the “is-a” argument must be sustainable. Once again our counter-example helps: the argument that a CAR_OWNER “is-a” CAR is not sustainable. • Our view of what “is-a” means will be particularly liberal. It will not, for example, disallow implementation inheritance — a form of inheritance that many people view with suspicion — as long as the “is-a” argument can reasonably be made. “Is-a” rule of inheritance Do not make a class B inherit from a class A unless you can somehow make the argument that one can view every instance of B also as an instance of A. “He has a head like an Austin Mini with the doors open”. Cartoon by Geoff Hocking; from The Dictionary of Aussie Slang, The Five Mile Press, Melbourne, Australia, reprinted with permission
812 USING INHERITANCE PROPERLY $24.2 These observations define both the usefulness and the limitations of the Is-a rule.It is useful as a negative rule in the Popperian style,enabling you to detect and reject inappropriate uses of inheritance.But as a positive rule it is not sufficient;not all suggested uses that pass the rule's test will be appropriate. Gratifying as the CAR OWNER counter-example may be,then,any feeling of elation that we may have gained from it will be short-lived.It was both the beginning and the end of the unmitigated good news-the news that some proposed uses of inheritance are obviously wrong and easy to spot.The rest of this chapter has to contend with the bad or at least mixed news:that in just about all other cases the decision is a true design issue, that is to say hard,although we will fortunately be able to find some general guidelines. 24.2 WOULD YOU RATHER BUY OR INHERIT? To choose between the two possible inter-module relations,client and inheritance,the basic rule is deceptively simple:client is has,inheritance isis.Why then is the choice not easy? To have and to be The reason is that whereas to have is not always to be,in many cases to be is also to have. No,this is neither some cheap attempt at existentialist philosophy nor a pitch to make you buy a house if you are currently renting;rather,simple observations on the difficulty of system modeling.We have already encountered an illustration of the first property- to have is not always to be-in the preceding example:a car owner has a car,but by no twist of reasoning or exposition can we assert that he is a car. What about the reverse situation?Take a simple statement about two object types from ordinary life,such as Every software engineer is an engineer. [A] whose truth we accept for its value as an example of the "is-a"relation (whatever our opinion may be as to the statement's accuracy).It seems hard indeed to think of a case which so clearly expresses"to be"rather than"to have".But now consider the following rephrasing of the property: In every software engineer there is an engineer [B] which can in turn be restated as Every software engineer has an "engineer"component. [C] Twisted,yes,and perhaps a trifle bizarre in its expression;but not fundamentally different from our premise [A]!So here it is:by changing our perspective slightly we can rephrase the“is”property as a"has
812 USING INHERITANCE PROPERLY §24.2 These observations define both the usefulness and the limitations of the Is-a rule. It is useful as a negative rule in the Popperian style, enabling you to detect and reject inappropriate uses of inheritance. But as a positive rule it is not sufficient; not all suggested uses that pass the rule’s test will be appropriate. Gratifying as the CAR_OWNER counter-example may be, then, any feeling of elation that we may have gained from it will be short-lived. It was both the beginning and the end of the unmitigated good news — the news that some proposed uses of inheritance are obviously wrong and easy to spot. The rest of this chapter has to contend with the bad or at least mixed news: that in just about all other cases the decision is a true design issue, that is to say hard, although we will fortunately be able to find some general guidelines. 24.2 WOULD YOU RATHER BUY OR INHERIT? To choose between the two possible inter-module relations, client and inheritance, the basic rule is deceptively simple: client is has, inheritance is is. Why then is the choice not easy? To have and to be The reason is that whereas to have is not always to be, in many cases to be is also to have. No, this is neither some cheap attempt at existentialist philosophy nor a pitch to make you buy a house if you are currently renting; rather, simple observations on the difficulty of system modeling. We have already encountered an illustration of the first property — to have is not always to be — in the preceding example: a car owner has a car, but by no twist of reasoning or exposition can we assert that he is a car. What about the reverse situation? Take a simple statement about two object types from ordinary life, such as Every software engineer is an engineer. [A] whose truth we accept for its value as an example of the “is-a” relation (whatever our opinion may be as to the statement’s accuracy). It seems hard indeed to think of a case which so clearly expresses “to be” rather than “to have”. But now consider the following rephrasing of the property: In every software engineer there is an engineer [B] which can in turn be restated as Every software engineer has an “engineer” component. [C] Twisted, yes, and perhaps a trifle bizarre in its expression; but not fundamentally different from our premise [A]! So here it is: by changing our perspective slightly we can rephrase the “is” property as a “has
$24.2 WOULD YOU RATHER BUY OR INHERIT? 813 “COMPOSITE If we look at the picture through the eyes of a programmer,we may summon an OBJECTS AND object diagram,in the style of those which served to discuss the dynamic model in an EXPANDED TYPES”,&7,page earlier chapter,showing a typical instance of a class and its components: )5d A“software engineer” object as aggregate (ENGINEER) (POET) (PLUMBER) (SOFTWARE ENGINEER) This shows an instance of SOFTWARE ENGINEER with various subobjects, representing the various posited aspects of a software engineer's personality and tasks Rather than subobjects(the expanded view)we might prefer to think in terms ofreferences: Another possible view (POET (SOFTWARE ENGINEER) (ENGINEER) (PLUMBER) Take both of these representations as ways to visualize the situation as seen from an implementation-oriented mindset,nothing more.Both suggest,however,that a client, or"has",interpretation-every software engineer has an engineer as one of his parts- is faithful to the original statement.The same observation can be made for any similar “is-a”relationship. So this is why the problem of choosing between client and inheritance is not trivial: when the "is"view is legitimate,one can always take the "has"view instead
§24.2 WOULD YOU RATHER BUY OR INHERIT? 813 If we look at the picture through the eyes of a programmer, we may summon an object diagram, in the style of those which served to discuss the dynamic model in an earlier chapter, showing a typical instance of a class and its components: This shows an instance of SOFTWARE_ENGINEER with various subobjects, representing the various posited aspects of a software engineer’s personality and tasks. Rather than subobjects (the expanded view) we might prefer to think in terms of references: Take both of these representations as ways to visualize the situation as seen from an implementation-oriented mindset, nothing more. Both suggest, however, that a client, or “has”, interpretation — every software engineer has an engineer as one of his parts — is faithful to the original statement. The same observation can be made for any similar “is-a” relationship. So this is why the problem of choosing between client and inheritance is not trivial: when the “is” view is legitimate, one can always take the “has” view instead. “COMPOSITE OBJECTS AND EXPANDED TYPES”, 8.7, page 254 A “software engineer” object as aggregate (SOFTWARE_ENGINEER) (ENGINEER) (POET) (PLUMBER) Another possible view (SOFTWARE_ENGINEER) (ENGINEER) (POET) (PLUMBER)
814 USING INHERITANCE PROPERLY $24.2 The reverse is not true:when"has"is legitimate,"is"is not always applicable,as the CAR OWNER example shows so clearly.This observation takes care ofthe easy mistakes, obvious to anyone having understood the basic concepts,and perhaps even explainable to authors of undergraduate texts.But whenever"is"does apply it is not the only contender. So two reasonable and competent people may disagree,one wanting to use inheritance, the other preferring client. Two criteria fortunately exist to help in such discussions.Not surprisingly (since they address a broad design issue)they may sometimes fail to give a clear,single solution. But in many practical cases they do tell you,beyond any hesitation,which of the two relations is the right one. Conveniently,one of these two criteria favors inheritance,and the other favors client. The rule of change The first observation is that the client relation usually permits change,while the inheritance relation does not.Here we must be careful with our use of the verbs"to be" and"to have"from ordinary language;so far they have helped us characterize the general nature of our two software relations,but software rules are,as always,more precise than their general non-software counterparts. One of the defining properties of inheritance is that it is a relation between classes, not objects.We have interpreted the property "Class B inherits from class 4"as meaning "every B object is an A object",but must remember that it is not in the power of any such object to change that property:only a change of the class can achieve such a result.The property characterizes the software,not any particular execution. With the client relation,the constraints are looser.If an object of type B has a component of type (either a subobject or an object reference),it is quite possible to change that component;the only restrictions are those of the type system,ensuring provably reliable execution(and govemned,through an interesting twist,by the inheritance structure) So even though a given inter-object relationship can result from either inheritance or client relationships between the corresponding classes,the effect will be different as to what can be changed and what cannot.For example our fictitious object structure Object and subobject (ENGINEER) (Other components omitted) (SOFTWARE ENGINEER)
814 USING INHERITANCE PROPERLY §24.2 The reverse is not true: when “has” is legitimate, “is” is not always applicable, as the CAR_OWNER example shows so clearly. This observation takes care of the easy mistakes, obvious to anyone having understood the basic concepts, and perhaps even explainable to authors of undergraduate texts. But whenever “is” does apply it is not the only contender. So two reasonable and competent people may disagree, one wanting to use inheritance, the other preferring client. Two criteria fortunately exist to help in such discussions. Not surprisingly (since they address a broad design issue) they may sometimes fail to give a clear, single solution. But in many practical cases they do tell you, beyond any hesitation, which of the two relations is the right one. Conveniently, one of these two criteria favors inheritance, and the other favors client. The rule of change The first observation is that the client relation usually permits change, while the inheritance relation does not. Here we must be careful with our use of the verbs “to be” and “to have” from ordinary language; so far they have helped us characterize the general nature of our two software relations, but software rules are, as always, more precise than their general non-software counterparts. One of the defining properties of inheritance is that it is a relation between classes, not objects. We have interpreted the property “Class B inherits from class A” as meaning “every B object is an A object”, but must remember that it is not in the power of any such object to change that property: only a change of the class can achieve such a result. The property characterizes the software, not any particular execution. With the client relation, the constraints are looser. If an object of type B has a component of type A (either a subobject or an object reference), it is quite possible to change that component; the only restrictions are those of the type system, ensuring provably reliable execution (and governed, through an interesting twist, by the inheritance structure). So even though a given inter-object relationship can result from either inheritance or client relationships between the corresponding classes, the effect will be different as to what can be changed and what cannot. For example our fictitious object structure Object and subobject (SOFTWARE_ENGINEER) (ENGINEER) (Other components omitted)
$24.2 WOULD YOU RATHER BUY OR INHERIT? 815 could result from an inheritance relationship between the corresponding classes: class SOFTWARE ENGINEER I inherit ENGINEER ENGINEER feature 44 end--class SOFTWARE ENGINEER I SOFTWARE ENGINEER but it could just as well have been obtained through the client relation: class SOFTWARE ENGINEER 2 feature the_engineer in me:ENGINEER end--class SOFTWARE ENGINEER 2 which could in fact be class SOFTWARE ENGINEER 3 feature 、SOFTWARE ENGINEER3 the truly important part of me:VOCATION VOCATION end--class SOFTWARE ENGINEER 3 provided we satisfy the type rules by making class ENGINEER a descendant of class VOCATION. Strictly speaking the last two variants represent a slightly different situation from the first if we assume that none of the given classes is expanded:instead of subobjects,the "software engineer"objects will in the last two cases contain references to "engineer" objects,as in the second figure of page 813.The introduction of references,however, does not fundamentally affect this discussion. With the first class definition,because the inheritance relationship holds between the generating classes,it is not possible to modify the object relationship dynamically:once an engineer,always an engineer. But with the other two definitions such a modification is possible:a procedure of the "software engineer"class can assign a new value to the corresponding object field (the field for the engineer in me or the truly important part of me).In the case of class SOFTWARE ENGINEER 2 the new value must be of type ENGINEER or compatible; but with class SOFTWARE ENGINEER 3 it may be of any type compatible with VOCAT/ON.So our software can model the idea of a software engineer who,after many years of pretending to be an engineer,finally sheds that part of his personality in favor of something that he deems more representative of his work,such as poet or plumber
§24.2 WOULD YOU RATHER BUY OR INHERIT? 815 could result from an inheritance relationship between the corresponding classes: class SOFTWARE_ENGINEER_1 inherit ENGINEER feature … end -- class SOFTWARE_ENGINEER_1 but it could just as well have been obtained through the client relation: class SOFTWARE_ENGINEER_2 feature the_engineer_in_me: ENGINEER … end -- class SOFTWARE_ENGINEER_2 which could in fact be class SOFTWARE_ENGINEER_3 feature the_truly_important_part_of_me: VOCATION … end -- class SOFTWARE_ENGINEER_3 provided we satisfy the type rules by making class ENGINEER a descendant of class VOCATION. Strictly speaking the last two variants represent a slightly different situation from the first if we assume that none of the given classes is expanded: instead of subobjects, the “software engineer” objects will in the last two cases contain references to “engineer” objects, as in the second figure of page 813. The introduction of references, however, does not fundamentally affect this discussion. With the first class definition, because the inheritance relationship holds between the generating classes, it is not possible to modify the object relationship dynamically: once an engineer, always an engineer. But with the other two definitions such a modification is possible: a procedure of the “software engineer” class can assign a new value to the corresponding object field (the field for the_engineer_in_me or the_truly_important_part_of_me). In the case of class SOFTWARE_ENGINEER_2 the new value must be of type ENGINEER or compatible; but with class SOFTWARE_ENGINEER_3 it may be of any type compatible with VOCATION. So our software can model the idea of a software engineer who, after many years of pretending to be an engineer, finally sheds that part of his personality in favor of something that he deems more representative of his work, such as poet or plumber. ENGINEER SOFTWARE_ENGINEER_1 SOFTWARE_ENGINEER_3 VOCATION
816 USING INHERITANCE PROPERLY $24.2 This yields our first criterion: Rule of change Do not use inheritance to describe a perceived "is-a"relation if the corresponding object components may have to be changed at run time. Only use inheritance if the corresponding inter-object relation is permanent.In other cases,use the client relation. The really interesting case is the one illustrated by SOFTWARE ENGINEER 3.With SOFTWARE ENGINEER 2 you can only replace the engineer component with another ofexactly same type.But in the SOFTWARE_ENGINEER_3 scheme,IOCATION should be a high-level class,most likely deferred;so the attribute can(through polymorphism) represent objects of many possible types,all conforming to IOCATION. This also means that even though this solution uses client as the primary relation,in practice its final form will often use inheritance as a complement.This will be particularly clear when we come to the notion of handle. The polymorphism rule Now for a criterion that will require inheritance and exclude client.That criterion is simple:polymorphic uses.In our study of inheritance we have seen that with a declaration of the form x:C x denotes at run time (assuming class C is not expanded)a potentially polymorphic reference;that is to say,x may become attached to direct instances not just of C but ofany proper descendants of C.This property is of course a key contribution to the power and flexibility of the object-oriented method,especially through its corollary,the possibility of defining polymorphic data structures,such as a LIST[C]which may contains instances of any of C's descendants. In our example,this means that with the SOFTWARE ENGINEER solution-the form of the class which inherits from ENGINEER-a client can declare an entity eng:ENGINEER which may become attached at run time to an object of type SOFTWARE ENGINEER 1. Or we can have a list of engineers,or a database of engineers,which includes a few mechanical engineers,a few chemical engineers,and a few software engineers as well. A reminder on methodology:the use of non-software words is a good help for understanding the concepts,but we should not let ourselves get carried away by such anthropomorphic examples;the objects of interest are software objects.So although we may loosely understand the words"a software engineer"for what they say,they actually denote an instance of SOFTWARE ENGINEER 1,that is to say,a software object somehow modeling a real person
816 USING INHERITANCE PROPERLY §24.2 This yields our first criterion: Only use inheritance if the corresponding inter-object relation is permanent. In other cases, use the client relation. The really interesting case is the one illustrated by SOFTWARE_ENGINEER_3. With SOFTWARE_ENGINEER_2 you can only replace the engineer component with another of exactly same type. But in the SOFTWARE_ENGINEER_3 scheme, VOCATION should be a high-level class, most likely deferred; so the attribute can (through polymorphism) represent objects of many possible types, all conforming to VOCATION. This also means that even though this solution uses client as the primary relation, in practice its final form will often use inheritance as a complement. This will be particularly clear when we come to the notion of handle. The polymorphism rule Now for a criterion that will require inheritance and exclude client. That criterion is simple: polymorphic uses. In our study of inheritance we have seen that with a declaration of the form x: C x denotes at run time (assuming class C is not expanded) a potentially polymorphic reference; that is to say, x may become attached to direct instances not just of C but of any proper descendants of C. This property is of course a key contribution to the power and flexibility of the object-oriented method, especially through its corollary, the possibility of defining polymorphic data structures, such as a LIST [C] which may contains instances of any of C’s descendants. In our example, this means that with the SOFTWARE_ENGINEER_1 solution — the form of the class which inherits from ENGINEER — a client can declare an entity eng: ENGINEER which may become attached at run time to an object of type SOFTWARE_ENGINEER_1. Or we can have a list of engineers, or a database of engineers, which includes a few mechanical engineers, a few chemical engineers, and a few software engineers as well. A reminder on methodology: the use of non-software words is a good help for understanding the concepts, but we should not let ourselves get carried away by such anthropomorphic examples; the objects of interest are software objects. So although we may loosely understand the words “a software engineer” for what they say, they actually denote an instance of SOFTWARE_ENGINEER_1, that is to say, a software object somehow modeling a real person. Rule of change Do not use inheritance to describe a perceived “is-a” relation if the corresponding object components may have to be changed at run time
$24.3 AN APPLICATION:THE HANDLE TECHNIQUE 817 Such polymorphic effects require inheritance:with SOFTWARE ENGINEER 2 or SOFTWARE ENGINEER 3 there is no way an entity or data structure of type ENGINEER can directly denote"software engineer"objects. Generalizing these observations-which are not,of course,specific to the example -yields the complement of the rule of change: Polymorphism rule Inheritance is appropriate to describe a perceived"is-a"relation if entities or data structure components of the more general type may need to become attached to objects of the more specialized type. Summary Although it brings no new concept,the following rule will be convenient as a summary of this discussion of criteria for and against inheritance. Choosing between client and inheritance In deciding how to express the dependency of a class B on a class A,apply the following criteria: CIl.If every instance of B initially has a component of type A,but that component may need to be replaced at run time by an object of a different type,make B a client of A. CI2.If there is a need for entities of type 4 to denote objects of type B, or for polymorphic structures containing objects of type 4 of which some may be of type B,make B an heir of 4. 24.3 AN APPLICATION:THE HANDLE TECHNIQUE Here is an example using the preceding rule.It yields a design pattern of wide applicability:handles. The first design of the Vision library for platform-independent graphics encountered a general problem:how to account for platform dependencies.The first solution used multiple inheritance in the following way:a typical class,such as the one describing windows,would have a parent describing the platform-independent properties of the corresponding abstraction,and another providing the platform-specific elements. elass WINDOW inherit GENERAL WINDOW PLATFORM WINDOW feature end -class WINDOW
§24.3 AN APPLICATION: THE HANDLE TECHNIQUE 817 Such polymorphic effects require inheritance: with SOFTWARE_ENGINEER_2 or SOFTWARE_ENGINEER_3 there is no way an entity or data structure of type ENGINEER can directly denote “software engineer” objects. Generalizing these observations — which are not, of course, specific to the example — yields the complement of the rule of change: Summary Although it brings no new concept, the following rule will be convenient as a summary of this discussion of criteria for and against inheritance. 24.3 AN APPLICATION: THE HANDLE TECHNIQUE Here is an example using the preceding rule. It yields a design pattern of wide applicability: handles. The first design of the Vision library for platform-independent graphics encountered a general problem: how to account for platform dependencies. The first solution used multiple inheritance in the following way: a typical class, such as the one describing windows, would have a parent describing the platform-independent properties of the corresponding abstraction, and another providing the platform-specific elements. class WINDOW inherit GENERAL_WINDOW PLATFORM_WINDOW feature … end -- class WINDOW Polymorphism rule Inheritance is appropriate to describe a perceived “is-a” relation if entities or data structure components of the more general type may need to become attached to objects of the more specialized type. Choosing between client and inheritance In deciding how to express the dependency of a class B on a class A, apply the following criteria: CI1 • If every instance of B initially has a component of type A, but that component may need to be replaced at run time by an object of a different type, make B a client of A. CI2 • If there is a need for entities of type A to denote objects of type B, or for polymorphic structures containing objects of type A of which some may be of type B, make B an heir of A
818 USING INHERITANCE PROPERLY $24.3 Platform GENERAL PLATFORM adaptation WINDOW WINDOW through inheritance WINDOW Class GENERAL WINDOW and similar ones such as GENERAL BUTTON are On the platform- deferred:they express all that can be said about the corresponding graphical objects and specific libraries WEL and MEL see the applicable operations without reference to a particular graphical platform.Classes “Object-oriented re- such as PLATFORM WINDOW provide the link to a graphical platform such as Windows,OS/2-Presentation-Manager or Unix-Motif,they give access to the platform-page44 specific mechanisms(encapsulated through a library such as WEL or MEL). A class such as WINDOW will then combine its two parents through features which effect (implement)the deferred features of GENERAL WINDOW by using the implementation mechanisms provided by PLATFORM WINDOW. PLATFORM WINDOW (like all other similar classes)needs several variants,one On the notion ofAce for each platform.These identically named classes will be stored in different directories; see“Assembling a the Ace for a compilation (the control file)will select the appropriate one. system".page 198 This solution works,but it has the drawback of tying the notion of WINDOW closely to the chosen platform.To transpose an earlier comment about inheritance:once a Motif window,always a Motif window.This may not be too bad,as it is hard to imagine a Unix window which,suddenly seized by middle-age anxiety,decides to become an OS/2 window.The picture becomes less absurd if we expand our definition of"platform"to include formats such as Postscript or HTML;then a graphical object could change representation for purposes of printing or inclusion in a Web document. The observation that we might need a looser connection between GUI objects such as a window and the underlying toolkit suggests trying the client relation.An inheritance link will remain,between WINDOW and GENERAL WINDOW;but the platform dependency will be represented by a client link to a class TOOLK/T representing the underlying "toolkit"(graphical platform).The figure at the top of the facing page illustrates the resulting structure,involving both client and inheritance. An interesting aspect of this solution is that it recognizes the notion of toolkit as a full- fledged abstraction,represented by a deferred class TOOLK/T.Each specific toolkit is then represented by an effective descendant of TOOLKIT such as MOTIF or MS WINDOWS. Here is how it works.Each class describing graphical objects,such as WINDOW,has an attribute providing access to the underlying platform: handle:TOOLKIT
818 USING INHERITANCE PROPERLY §24.3 Class GENERAL_WINDOW and similar ones such as GENERAL_BUTTON are deferred: they express all that can be said about the corresponding graphical objects and the applicable operations without reference to a particular graphical platform. Classes such as PLATFORM_WINDOW provide the link to a graphical platform such as Windows, OS/2-Presentation-Manager or Unix-Motif; they give access to the platformspecific mechanisms (encapsulated through a library such as WEL or MEL). A class such as WINDOW will then combine its two parents through features which effect (implement) the deferred features of GENERAL_WINDOW by using the implementation mechanisms provided by PLATFORM_WINDOW. PLATFORM_WINDOW (like all other similar classes) needs several variants, one for each platform. These identically named classes will be stored in different directories; the Ace for a compilation (the control file) will select the appropriate one. This solution works, but it has the drawback of tying the notion of WINDOW closely to the chosen platform. To transpose an earlier comment about inheritance: once a Motif window, always a Motif window. This may not be too bad, as it is hard to imagine a Unix window which, suddenly seized by middle-age anxiety, decides to become an OS/2 window. The picture becomes less absurd if we expand our definition of “platform” to include formats such as Postscript or HTML; then a graphical object could change representation for purposes of printing or inclusion in a Web document. The observation that we might need a looser connection between GUI objects such as a window and the underlying toolkit suggests trying the client relation. An inheritance link will remain, between WINDOW and GENERAL_WINDOW; but the platform dependency will be represented by a client link to a class TOOLKIT representing the underlying “toolkit” (graphical platform). The figure at the top of the facing page illustrates the resulting structure, involving both client and inheritance. An interesting aspect of this solution is that it recognizes the notion of toolkit as a fullfledged abstraction, represented by a deferred class TOOLKIT. Each specific toolkit is then represented by an effective descendant of TOOLKIT such as MOTIF or MS_WINDOWS. Here is how it works. Each class describing graphical objects, such as WINDOW, has an attribute providing access to the underlying platform: handle: TOOLKIT WINDOW PLATFORM_ WINDOW ∗ GENERAL_ WINDOW On the platformspecific libraries WEL and MEL see “Object-oriented rearchitecturing”, page 441 Platform adaptation through inheritance On the notion of Ace see “Assembling a system”, page 198