Docsity
Docsity

Prepare for your exams
Prepare for your exams

Study with the several resources on Docsity


Earn points to download
Earn points to download

Earn points by helping other students or get them with a premium plan


Guidelines and tips
Guidelines and tips

Inheritance and Substitution in Object-Oriented Programming, Schemes and Mind Maps of Construction

The concept of inheritance and substitution in object-oriented programming, focusing on the principle of substitution and its importance for ensuring the functional consistency of subclasses. It also touches upon the differences between inheritance and interfaces, abstract classes, and various examples in C++, C#, Delphi, and Java.

Typology: Schemes and Mind Maps

2021/2022

Uploaded on 09/27/2022

alberteinstein
alberteinstein 🇬🇧

4.8

(9)

227 documents

1 / 24

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Chapter 8
Inheritance and
Substitution
The rst step in learning object-oriented programming is understanding the basic
philosophy of organizing the performance of a task as the interaction of loosely
coupled software components. This organizational approach was the central
lesson in the case studies of Chapters 6 and 7.
The
next
step in learning object-oriented programming is organizing classes
into a hierarchical structure based on the concept of inheritance. By
inheritance
,
we mean the property that instances of a child class (or subclass) can access both
data and behavior (methods) associated with a parent class (or superclass).
8.1 An Intuitive Description of Inheritance
Let us return to Chris and Fred, the customer and orist from the rst chapter.
There is a certain behavior we expect orists to exhibit, not because they are
orists but simply because they are shopkeepers. For example, we expect Fred to
request money for a transaction and in turn give back a receipt. These activities
are not unique to orists, but are common to bakers, grocers, stationers, car
dealers, and other merchants. It is as though wehave associated certain behavior
with the general category
Shopkeeper
, and as
Florists
are a specialized form of
shopkeepers, the behavior is automatically identied with the subclass.
In programming languages, inheritance means that the behavior and data
associated with child classes are always an
extension
(that is, a larger set) of the
properties associated with parent classes. A subclass will have all the properties
of the parent class, and other properties as well. On the other hand, since a child
class is a more specialized (or restricted) form of the parent class, it is also, in a
certain sense, a
contraction
of the parenttype. This tension between inheritance
as expansion and inheritance as contraction is a source for much of the power
inherent in the technique, but at the same time it causes much confusion as to
161
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18

Partial preview of the text

Download Inheritance and Substitution in Object-Oriented Programming and more Schemes and Mind Maps Construction in PDF only on Docsity!

Chapter 8

Inheritance and

Substitution

The rst step in learning ob ject-oriented programming is understanding the basic philosophy of organizing the p erformance of a task as the interaction of lo osely coupled software comp onents. This organizational approach was the central lesson in the case studies of Chapters 6 and 7. The next step in learning ob ject-oriented programming is organizing classes into a hierarchical structure based on the concept of inheritance. By inheritance, we mean the prop erty that instances of a child class (or sub class) can access b oth data and b ehavior (metho ds) asso ciated with a parent class (or sup erclass).

8.1 An Intuitive Description of Inheritance

Let us return to Chris and Fred, the customer and orist from the rst chapter. There is a certain b ehavior we exp ect orists to exhibit, not b ecause they are orists but simply b ecause they are shopkeep ers. For example, we exp ect Fred to request money for a transaction and in turn give back a receipt. These activities are not unique to orists, but are common to bakers, gro cers, stationers, car dealers, and other merchants. It is as though we have asso ciated certain b ehavior with the general category Shopkeep er, and as Florists are a sp ecialized form of shopkeep ers, the b ehavior is automatically identi ed with the sub class. In programming languages, inheritance means that the b ehavior and data asso ciated with child classes are always an extension (that is, a larger set) of the prop erties asso ciated with parent classes. A sub class will have all the prop erties of the parent class, and other prop erties as well. On the other hand, since a child class is a more sp ecialized (or restricted) form of the parent class, it is also, in a certain sense, a contraction of the parent typ e. This tension b etween inheritance as expansion and inheritance as contraction is a source for much of the p ower inherent in the technique, but at the same time it causes much confusion as to

162 CHAPTER 8. INHERITANCE AND SUBSTITUTION

its prop er employment. We will see this when we examine a few of the uses of inheritance in a subsequent section. Inheritance is always transitive, so that a class can inherit features from sup erclasses many levels away. That is, if class Dog is a sub class of class Mammal, and class Mammal is a sub class of class Animal, then Dog will inherit attributes b oth from Mammal and from Animal.

8.1.1 The Is-a Test

As we noted in Chapter 2, there is a rule-of-thumb that is commonly used to test whether two concepts should b e linked by an inheritance relationship. This heuristic is termed the is-a test. The is-a test says that to tell if concept A should b e linked by inheritance to concept B, try forming the English sentence \A(n) A is a(n) B." If the sentence \sounds right" to your ear, then inheritance is most likely appropriate in this situation. For example, the following all seem like reasonable assertions:

A Bird is an Animal A Cat is a Mammal An Apple Pie is a Pie A TextWindow is a Window A Ball is a GraphicalOb ject An IntegerArray is an Array

On the other hand, the following assertions seem strange for one reason or another, and hence inheritance is likely not appropriate:

A Bird is a Mammal An Apple Pie is an Apple An Engine is a Car A Ball is a Wall An IntegerArray is an Integer

There are times when inheritance can reasonably b e used even when the is-a test fails. Nevertheless, for the vast ma jority of situations, it gives a reliable indicator for the appropriate use of the technique.

8.1.2 Reasons to Use Inheritance

Although there are many uses for the mechanism of inheritance, two motivations far outweigh all other concerns:

 Inheritance as a means of co de reuse. Because a child class can inherit b ehavior from a parent class, the co de do es not need to b e rewritten for the child. This can greatly reduce the amount of co de needed to develop a new idea.

164 CHAPTER 8. INHERITANCE AND SUBSTITUTION

Public, Private and Protected

In earlier chapters we have seen the use of the terms public and private. A public feature is accessible to co de outside the class de - nition, while a private feature is accessible only within the class def- inition. Inheritance intro duces a third alternative. In C++ (also in C#, Delphi, Ruby and several other languages) a protected feature is accessible only within a class de nition or within the de nition of any child classes. Thus a protected feature is more accessible than a private one, and less accessible than a public feature. This is illustrated by the following example:

class Parent f private: int three; protected: int two; public: int one; Parent () f one = two = three = 42; g void inParent () f cout << one << two << three; / all legal  / g g;

class Child : public Parent f public: void inChild () f cout << one; // legal cout << two; // legal cout << three; // error - not legal g g;

void main () f Child c; cout << c.one; // legal cout << c.two; // error - not legal cout << c.three; // error - not legal g The lines marked as error will generate compiler errors. The private feature can b e used only within the parent class. The protected feature only within the parent and child class. Only public features can b e used outside the class de nitions. Java uses the same keyword, but there protected features are legal within the same package in which they are declared.

8.3. SUBCLASS, SUBTYPE, AND SUBSTITUTION 165

C++

class Wall : public GraphicalObject { ... }

C#

class Wall : GraphicalObject { ... }

CLOS (defclass^ Wall^ (GraphicalObject)^ ()^ )

Java

class Wall extends GraphicalObject { ... }

Ob ject Pascal

type Wall = object (GraphicalObject) ... end;

Python

class Wall(GraphicalObject): def init(self): ...

Ruby

class Wall < GraphicalObject ... end

Figure 8.1: Syntax Used to Indicate Inheritance in Several Languages

8.4. OVERRIDING AND VIRTUAL METHODS 167

in the declared class GraphicalObject. For this co de to op erate correctly it is imp erative that the functionality of each of these sub classes match the exp ected functionality sp eci ed by the parent class; that is, the sub classes must also b e subtyp es. All ob ject oriented languages will supp ort the principle of substitution, al- though some will require additional syntax when a metho d is overridden. Most supp ort the concept in a very straight-forward fashion; the parent class simply holds a value from the child class. The one ma jor exception to this is the lan- guage C++. In C++ only p ointers and references truly supp ort substitution; variables that are simply declared as value (and not as p ointers) do not sup- p ort substitution. We will see why this prop erty is necessary in C++ in a later chapter.

8.3.1 Substitution and Strong Typing*

Statically typ ed languages (such as C++^ and Ob ject Pascal) place much more emphasis on the principle of substitution than do dynamically typ ed languages (such as Smalltalk and Ob jective-C). The reason for this is that statically typ ed languages tend to characterize ob jects by their class, whereas dynamically typ ed languages tend to characterize ob jects by their b ehavior. For example, a p oly- morphic function (a function that can take ob jects of various classes) in a stati- cally typ ed language can ensure a certain level of functionality only by insisting that all arguments b e sub classes of a given class. Since in a dynamically typ ed language arguments are not typ ed at all, the same requirement would b e simply that an argument must b e able to resp ond to a certain set of messages. An example of this di erence would b e a function that requires an argument b e an instance of a sub class of Measureable, as opp osed to a function that re- quires an argument understand the messages lessThan and equal. The former is characterizing an ob ject by its class, the latter is characterizing an ob ject by its b ehavior. Both forms of typ e checking are found in ob ject-oriented languages.

8.4 Overriding and Virtual Metho ds

In Chapter 1 we noted that child classes may sometimes nd it necessary to override the b ehavior they would otherwise inherit from their parent classes. In syntactic terms, what this means is that a child class will de ne a metho d using the same name and typ e signature as one found in the parent class. When overriding is combined with substitution, we have the situation where a variable is declared as one class, but holds a value from a child class, and a metho d matching a given message is found in b oth classes. In almost all cases what we want to have happ en in this situation is to execute the metho d found in the child class, ignoring the metho d from the parent class.

(^0) Section headings followed by an asterisk indicate optional material.

168 CHAPTER 8. INHERITANCE AND SUBSTITUTION

C++

class GraphicalObject { public: virtual void draw(); };

class Ball : public Graphicalobject { public: virtual void draw(); // virtual optional here };

C#

class GraphicalObject { public viritual void draw () { ... } }

class Ball : Graphical Object { public override void draw () { ... } }

Delphi

type GraphicalObject = class (TObject) ... procedure draw; virtual; end;

Ball = class (GraphicalObject) ... procedure draw; override; end;

Ob ject Pascal

type GraphicalObject = object ... procedure draw; end;

Ball = object (GraphicalObject) ... procedure draw; override; end;

Figure 8.2: Overriding in Various Languages

170 CHAPTER 8. INHERITANCE AND SUBSTITUTION

virtual void paint () = 0; // assignment makes it pure virtual g;

A class can have b oth abstract (or pure virtual) metho ds and non-abstract metho ds. A class in which all metho ds were declared as abstract (or pure virtual) would corresp ond to the Java idea of an interface. Abstract metho ds can b e simulated even when the language do es not pro- vide explicit supp ort for the concept. In Smalltalk, for example, programmers frequently de ne a metho d so as to generate an error if it is invoked, with the exp ectation that it will b e overwritten in child classes:

writeTo: stream " self error: sub class must override writeTo

This is not exactly the same as a true abstract metho d, since it do es not preclude the creation of instances of the class. Nevertheless, if an instance is created and this metho d invoked the program will quickly fail, and hence such errors are easily detected.

8.6 Forms of Inheritance

Inheritance is used in a surprising variety of ways. In this section we will describ e a few of its more common uses. Note that the following list represents general abstract categories and is not intended to b e exhaustive. Furthermore, it some- times happ ens that two or more descriptions are applicable to a single situation, b ecause some metho ds in a single class use inheritance in one way while others use it in another.

8.6.1 Sub classing for Sp ecialization (Subtyping)

Probably the most common use of inheritance and sub classing is for sp ecializa- tion. In sub classing for sp ecialization, the new class is a sp ecialized form of the parent class but satis es the sp eci cations of the parent in all relevant resp ects. Thus, in this form the principle of substitution is explicitly upheld. Along with the following category (sub classing for sp eci cation) this is the most ideal form of inheritance, and something that a go o d design should strive for. Here is an example of sub classing for sp ecialization. A class Window pro- vides general windowing op erations (moving, resizing, iconi cation, and so on). A sp ecialized sub class TextEditWindow inherits the window op erations and in addition, provides facilities that allow the window to display textual material and the user to edit the text values. Because the text edit window satis es all the prop erties we exp ect of a window in general (thus, a TextEditWindow win- dow is a subtyp e of Window in addition to b eing a sub class), we recognize this situation as an example of sub classing for sp ecialization.

8.6. FORMS OF INHERITANCE 171

8.6.2 Sub classing for Sp eci cation

Another frequent use for inheritance is to guarantee that classes maintain a cer- tain common interface{that is, they implement the same metho ds. The parent class can b e a combination of implemented op erations and op erations that are deferred to the child classes. Often, there is no interface change of any sort b e- tween the parent class and the child class{the child merely implements b ehavior describ ed, but not implemented, in the parent. This is in essence a sp ecial case of sub classing for sp ecialization, except that the sub classes are not re nements of an existing typ e but rather realizations of an incomplete abstract sp eci cation. In such cases the parent class is sometimes known as an abstract speci cation class. A class that implements an interface is always ful lling this form of inher- itance. However, sub classing for sp eci cation can also arise in other ways. In the billiards simulation example presented in Chapter 7, for example, the class GraphicalObject was an abstract class since it describ ed, but did not implement, the metho ds for drawing the ob ject and resp onding to a hit by a ball. The sub- sequent classes Ball, Wall, and Hole then used sub classing for sp eci cation when they provided meanings for these metho ds. In general, sub classing for sp eci cation can b e recognized when the parent class do es not implement actual b ehavior but merely de nes the b ehavior that will b e implemented in child classes.

8.6.3 Sub classing for Construction

A class can often inherit almost all of its desired functionality from a parent class p erhaps changing only the names of the metho ds used to interface to the class, or mo difying the arguments in a certain fashion. This may b e true even if the new class and the parent class fail to share the is-a relationship. For example, the Smalltalk class hierarchy implements a generalization of an array called Dictionary. A dictionary is a collection of key-value pairs, like an array, but the keys can b e arbitrary values. A symbol table, such as might b e used in a compiler, can b e considered a dictionary indexed by symb ol names in which the values have a xed format (the symb ol-table entry record). A class Symb olTable can therefore b e made a sub class of the class Dictionary, with new metho ds de ned that are sp eci c to the use as a symb ol table. Another example might b e forming a set data abstraction on top of a base class which provides list metho ds. In b oth these cases, the child class is not a more sp ecialized form of the parent class, b ecause we would never think of substituting an instance of the child class in a situation where an instance of the parent class is b eing used. A common use of sub classing for construction o ccurs when classes are created to write values to a binary le, for example, in a p ersistent storage system. A parent class may implement only the ability to write raw binary data. A sub class is constructed for every structure that is saved. The sub class implements a save pro cedure for the data typ e, which uses the b ehavior of the parent typ e to do

8.6. FORMS OF INHERITANCE 173

8.6.5 Sub classing for Extension

While sub classing for generalization mo di es or expands on the existing func- tionality of an ob ject, sub classing for extension adds totally new abilities. Sub- classing for extension can b e distinguished from sub classing for generalization in that the latter must override at least one metho d from the parent and the functionality is tied to that of the parent. Extension simply adds new metho ds to those of the parent, and the functionality is less strongly tied to the existing metho ds of the parent. An example of sub classing for extension is a StringSet class that inherits from a generic Set class but is sp ecialized for holding string values. Such a class might provide additional metho ds for string-related op erations{for example, \search by pre x," which returns a subset of all the elements of the set that b egin with a certain string value. These op erations are meaningful for the sub class, but are not particularly relevant to the parent class. As the functionality of the parent remains available and untouched, sub class- ing for extension do es not contravene the principle of substitution and so such sub classes are always subtyp es.

8.6.6 Sub classing for Limitation

Sub classing for limitation o ccurs when the b ehavior of the sub class is smaller or more restrictive than the b ehavior of the parent class. Like sub classing for gener- alization, sub classing for limitation o ccurs most frequently when a programmer is building on a base of existing classes that should not, or cannot, b e mo di ed. For example, an existing class library provides a double-ended-queue, or deque, data structure. Elements can b e added or removed from either end of the deque, but the programmer wishes to write a stack class, enforcing the prop- erty that elements can b e added or removed from only one end of the stack. In a manner similar to sub classing for construction, the programmer can make the Stack class a sub class of the existing Deque class, and can mo dify or override the undesired metho ds so that they pro duce an error message if used. These metho ds override existing metho ds and eliminate their functionality, which characterizes sub classing for limitation. (Overriding, by which a sub class changes the meaning of a metho d de ned in a parent class, will b e discussed in a subsequent chapter). Because sub classing for limitation is an explicit contravention of the principle of substitution, and b ecause it builds sub classes that are not subtyp es, it should b e avoided whenever p ossible.

8.6.7 Sub classing for Variance

Sub classing for variance is employed when two or more classes have similar im- plementations but do not seem to p ossess any hierarchical relationships b etween the abstract concepts represented by the classes. The co de necessary to control a mouse, for example, may b e nearly identical to the co de required to control

174 CHAPTER 8. INHERITANCE AND SUBSTITUTION

a graphics tablet. Conceptually, however, there is no reason why class Mouse should b e made a sub class of class Tablet, or the other way. One of the two classes is then arbitrarily selected to b e the parent, with the common co de b eing inherited by the other and device-sp eci c co de b eing overridden. Usually, however, a b etter alternative is to factor out the common co de into an abstract class, say PointingDevice, and to have b oth classes inherit from this common ancestor. As with sub classing for generalization, this choice may not b e available if you are building on a base of existing classes.

8.6.8 Sub classing for Combination

A common situation is a sub class that represents a combination of features from two or more parent classes. A teaching assistant, for example, may have charac- teristics of b oth a teacher and a student, and can therefore logically b ehave as b oth. The ability of a class to inherit from two or more parent classes is known as multiple inheritance; it is suciently subtle and complex that we will devote an entire chapter to the concept.

8.6.9 Summary of the Forms of Inheritance

We can summarize the various forms of inheritance by the following table:

 Sp ecialization. The child class is a sp ecial case of the parent class; in other words, the child class is a subtyp e of the parent class.

 Sp eci cation. The parent class de nes b ehavior that is implemented in the child class but not in the parent class.

 Construction. The child class makes use of the b ehavior provided by the parent class, but is not a subtyp e of the parent class.

 Generalization. The child class mo di es or overrides some of the metho ds of the parent class.

 Extension. The child class adds new functionality to the parent class, but do es not change any inherited b ehavior.

 Limitation. The child class restricts the use of some of the b ehavior inher- ited from the parent class.

 Variance. The child class and parent class are variants of each other, and the class-sub class relationship is arbitrary.

 Combination. The child class inherits features from more than one parent class. This is multiple inheritance and will b e the sub ject of a later chapter.

176 CHAPTER 8. INHERITANCE AND SUBSTITUTION

8.7.2 Inheritance and Constructors

A constructor, you will recall, is a pro cedure that is invoked implicitly during the creation of a new ob ject value, and which guarantees that the newly created ob ject is prop erly initialized. Inheritance complicates this pro cess, since b oth the parent and the new child class may have initialization co de to p erform. Thus co de from b oth classes must b e executed. In Java, C++ and other languages the constructor for b oth parent and child will automatically b e executed as long as the parent constructor do es not require additional parameters. When the parent do es require parameters, the child must explicitly provide them. In Java this is done using the keyword sup er:

class Child extends Parent f public Child (int x) f super (x + 2); // invoke parent constructor ... g g

In C++ the same task is accomplished by writing the parent class name in the form of an initializer:

class Child : public Parent f public: Child (int x) : Parent(x+2) f ... g g;

In Delphi a constructor for a child class must always invoke the constructor for the parent class, even if the parent class constructor takes no arguments. The syntax is the same for executing the parent class b ehavior in any overridden metho d:

constructor TChildClass.Create; begin inherited Create; // execute constructor in parent end

Arguments to the parent constructor are added as part of the call:

constructor TChildClass.Create (x : Integer); begin inherited Create(x + 2); end

8.7. VARIATIONS ON INHERITANCE* 177

Similarly, an initialization metho d in Python do es not automatically invoke the function in the parent, hence the programmer must not forget to do this task:

class Child(Parent): def init (self):

first initialize parent

Parent. init (self)

then do our initialization

...

8.7.3 Virtual Destructors

Recall from Chapter 5 that in C++ a destructor is a function that will b e invoked just b efore the memory for a variable is recovered. Destructors are used to p erform whatever tasks are necessary to ensure a value is prop erly deleted. For example, a destructor will frequently free any dynamically allo cated memory the variable may hold. If substitution and overriding are anticipated, then it is imp ortant that the destructor b e declared as virtual. Failure to do so may result in destructors for child classes not b eing invoked. This following example shows this error:

class Parent f public: // warning, destructor not declared virtual Parent () f cout << "in parent\n"; g g;

class Child : public Parent f public: Child () f cout << "in child\n"; g g;

If an instance of the child class is held by a p ointer to the parent class and subsequently released (say, by a delete statement), then only the parent destructor will b e invoked.

Parent  p = new Child(); delete p; in parent

If the parent destructor is declared as virtual, then b oth the parent and child destructors will b e executed. In C++ it is a go o d idea to include a virtual

8.8. THE BENEFITS OF INHERITANCE 179

Already, several such libraries are commercially available, and we can exp ect many more sp ecialized systems to app ear in time.

8.8.5 Rapid Prototyping

When a software system is constructed largely out of reusable comp onents, devel- opment time can b e concentrated on understanding the new and unusual p ortion of the system. Thus, software systems can b e generated more quickly and easily, leading to a style of programming known as rapid prototyping or exploratory pro- gramming. A prototyp e system is develop ed, users exp eriment with it, a second system is pro duced that is based on exp erience with the rst, further exp eri- mentation takes place, and so on for several iterations. Such programming is particularly useful in situations where the goals and requirements of the system are only vaguely understo o d when the pro ject b egins.

8.8.6 Polymorphism and Frameworks

Software pro duced conventionally is generally written from the b ottom up, al- though it may b e designed from the top down. That is, the lower-level routines are written, and on top of these slightly higher abstractions are pro duced, and on top of these even more abstract elements are generated. This pro cess is like building a wall, where every brick must b e laid on top of an already laid brick.

Normally, co de p ortability decreases as one moves up the levels of abstraction. That is, the lowest-level routines may b e used in several di erent pro jects, and p erhaps even the next level of abstraction may b e reused, but the higher-level routines are intimately tied to a particular application. The lower-level pieces can b e carried to a new system and generally make sense standing on their own; the higher-level comp onents generally make sense (b ecause of declarations or data dep endencies) only when they are built on top of sp eci c lower-level units.

Polymorphism in programming languages p ermits the programmer to gener- ate high-level reusable comp onents that can b e tailored to t di erent applica- tions by changes in their low-level parts. We will have much more to say ab out this topic in subsequent chapters.

8.8.7 Information Hiding

A programmer who reuses a software comp onent needs only to understand the nature of the comp onent and its interface. It is not necessary for the programmer to have detailed information concerning matters such as the techniques used to implement the comp onent. Thus, the interconnectedness b etween software sys- tems is reduced. We earlier identi ed the interconnected nature of conventional software as b eing one of the principle causes of software complexity.

180 CHAPTER 8. INHERITANCE AND SUBSTITUTION

8.9 The Costs of Inheritance

Although the b ene ts of inheritance in ob ject-oriented programming are great, almost nothing is without cost of one sort or another. For this reason, we must consider the cost of ob ject-oriented programming techniques, and in particular the cost of inheritance.

8.9.1 Execution Sp eed

It is seldom p ossible for general-purp ose software to ols to b e as fast as carefully hand-crafted systems. Thus, inherited metho ds, which must deal with arbitrary sub classes, are often slower than sp ecialized co de. Yet, concern ab out eciency is often misplaced.^3 First, the di erence is often small. Second, the reduction in execution sp eed may b e balanced by an increase in the sp eed of software development. Finally, most programmers actually have little idea of how execution time is b eing used in their programs. It is far b etter to develop a working system, monitor it to discover where execution time is b eing used, and improve those sections, than to sp end an inordinate amount of time worrying ab out eciency early in a pro ject.

8.9.2 Program Size

The use of any software library frequently imp oses a size p enalty not imp osed by systems constructed for a sp eci c pro ject. Although this exp ense may b e substantial, as memory costs decrease the size of programs b ecomes less imp or- tant. Containing development costs and pro ducing high-quality and error-free co de rapidly are now more imp ortant than limiting the size of programs.

8.9.3 Message-Passing Overhead

Much has b een made of the fact that message passing is by nature a more costly op eration than simple pro cedure invo cation. As with overall execution sp eed, however, overconcern ab out the cost of message passing is frequently p enny-wise and p ound-fo olish. For one thing, the increased cost is often marginal{p erhaps two or three additional assembly-language instructions and a total time p enalty of 10 p ercent. (Timing gures vary from language to language. The overhead of message passing will b e much higher in dynamically b ound languages, such as Smalltalk, and much lower in statically b ound languages, such as C++.) This increased cost, like others, must b e weighed against the many b ene ts of the ob ject-oriented technique. A few languages, notably C++, make a numb er of options available to the programmer that can reduce the message-passing overhead. These include elim-

(^3) The following quote from an article by Bill Wulf o ers some apt remarks on the imp ortance of eciency: \More computing sins are committed in the name of eciency (without necessarily achieving it) than for any other single reason{including blind stupidity" [Wulf 1972 ].