diagram on page 84 to the design phase, and the prescription of Smalltalk-style method names in the diagram on page 85 to the implementation phase.

Rigid progressions from analysis to design to implementation, historically known as "waterfall" models of development, are out of vogue. Problems can rarely be fully understood until after users have examined a prototype. Nothing will expose more misunderstandings or fuzzy analysis or elicit more feedback than a working mock-up or prototype. For this reason, current design or analysis methods almost always emphasize "spiral" or "iterative" development, which explicitly acknowledge that what you learn from downstream phases induces rework of upstream phases.

The greatest shortcoming of CRC cards is also their greatest strength, namely, their disconnection from the biases and constraints of actual computer systems. They pro-voke discussions, but they leave little trace of these discussions. The cards fall out of date and are eventually lost, along with the ideas and associations they once engendered. Of course, a project is obligated to preserve as much of value as possible from those early CRC discussions. The prevailing schools of thought for solving this documentation problem are to: (1) produce computerized diagrams that illustrate the analysis or design, supplemented by text, (2) write thoughtful comments embedded in the code, or (3) combine these. There has never been a completely satisfactory solution, even before objects or CRC cards, and each project must set and enforce a suitable policy.

Any policy must rely heavily on the names and comments of methods. That's because these are practically the only development artifacts (along with class names) that are relevant and meaningful to everyone on the project—analysts, developers, testers. Everyone can understand them, and if anyone changes them, everyone else can understand the changes. Class and method names therefore constitute a common lan-guage for sharing the conceptual model (page 144) of the problem. A conceptual model that people do not have to translate for one another is a side-effect of a success-ful object-oriented project.

Good analyses and designs also treat the dynamic behavior of a system—that is, sequences of messages among several interacting objects. CRC cards promote rudi-mentary forms of dynamic design because the cards can be waved about and at one another while enacting scenarios, but one must again turn elsewhere to document the knowledge so acquired. More on this subject in Chapter 10.

The original CRC cards [Beck and Cunningham 1989] had two columns of text, the first listing responsibilities and the second collaborators; that is, classes on which the current class depends to fulfill its responsibilities. Variants abound, however. The simplification in this chapter, underplaying the collaborators, is among the least orthodox. Whether as part of using CRC cards or another method or at a later stage in design, the developer must think through collaborating classes. Rebecca Wirfs-Brock's
"responsibility-driven design" methodology follows the original card format, but also documents superclass and subclasses on the card, and suggests that collaborators be grouped with the responsibility they support. Her use of cards does not emphasize their physical manipulation, however. Her book [Wirfs-Brock et al. 1990] is a good source of larger CRC examples than this chapter's, and is also one of the standard textbooks on object-oriented design and analysis. Others include those by [Rumbaugh et al. 1991; Booch 1994; Jacobson et al. 1992; and Coad and Yourdon 1991].

Last but not least, failure as a necessary element of good design is the theme of [Petroski 1985]. He examines engineering failures, but the underlying principle is universal.
CHAPTER 8

Exercises—Implementing a design

You now have the basic skills to begin developing Smalltalk applications. Your first application will be a prototype of the application we designed in the preceeding chap- ter. Rather than spell out every detail of the implementation, I’ll just guide you through the mileposts and encourage you to think through the details. As you know by now, Smalltalk programmers explore a lot as they develop applications, so you should expect to explore and experiment as you proceed. Allow about three hours for this chapter.

8.1 Create the classes

q First create a new application for the work you are about to do.

q Then create both classes Account and Transaction .

q Define the instance variables for these classes. To review the appropriate instance variables, look at the figure on page 86, and to review how to create classes and instance variables, review your work in Chapter 4.

8.2 A test case

A good way to stay honest is to write a method you can use as a test case.

q Create a class method named example for the class Account . It won’t make sense to execute it yet, since none of the methods it invokes exist.
```java
example
    "Test by executing:

    Account example inspect

    |
    | account transaction|
    | account := Account newBalance: 2500.
    | transaction := Transaction newAmount: -300 date: Date today.
    | account handleTransaction: transaction.
    | ^account
```

This test uses class (factory) methods to create an account and a transaction, processes the transaction, and returns the account. The reason for so much white space in the comment is to make Account example inspect an easy target for highlighting with the mouse and executing. You can execute the method while you are browsing it, instead of having to move over to the Transcript every time you want to run a test. Not essential, but a convenient trick. Also notice that unlike most other new methods you've seen, the methods for creating new instances of Account and Transaction above expect arguments.

## 8.3 Write "new" methods

* Because you will be creating new instances of both classes in the application, write a "new" method for Account and Transaction. Remember that these are class methods, not instance methods. Here's an example of the method for class Account:

```java
newBalance: anInteger
    "Answer a new instance of the receiver with balance anInteger"
    ^self new initialBalance: anInteger
```

Notice that you will also need an instance method named initialBalance.

By the way, you don't have to use names with "new" in them, like newBalance, although it is common to do so for class methods that create new instances of the class.

## 8.4 Write instance methods

* Prepare instance methods for the classes Account and Transaction, according to our design. Refer to the CRC cards on page 85.
The `<=`, method often puzzles beginners. Remember that the design assumes that
transactions are smart enough to compare themselves with other transactions, for
which they need the binary method `<=`, in class `Transaction`, like so:

```python
<= anotherTransaction
    "Answer true if my date is before anotherTransaction's date,
     false otherwise"
...
```

But how? The code must explicitly compare `my` (the receiving transaction's) date with the date of the *other* transaction. How do I access the inside of *another* object? That's the basic prohibition of encapsulation: I can't. I can obtain the information only if the other object has a method that obliges. Thus transactions must also support a method of the form:

```
getDate
    ^date
```

## 8.5 Test your solution

Now run the test case by executing Account example inspect (or equivalently, inspect-ing Account example). An inspector window should open on an account, but if some- thing goes wrong, like getting a walkback, use it as an opportunity to practice your debugging skills. (Review the exercise on page 57 if necessary.) Once you have an inspector window on an account, verify that it holds your transaction. You can do so by double-clicking on the entries in the inspector; this action opens another inspector on whatever you double-clicked. By repeatedly double-clicking, you can drill down and examine the account's log, any transactions inside the log, and dates and amounts inside the transactions.

This first test was too simple to thoroughly test your code—one transaction doesn't make for an interesting sort. Write another test case, `example2`, similar to the first, but that handles at least two additional transactions with different dates. You can produce different dates in several ways: look through the class methods of `Date` or review your work with dates on page 56. Run `example2`, and double-click through inspector levels to verify that the log contains all your transactions, and that they occur in chronological order.
## 8.6 Engineering discipline

The Smalltalk environment, dynamic as it is, encourages programmers to try changes quickly, sometimes at the expense of sound engineering practices. For example, unless cautioned otherwise, many students modify example directly instead of writing an *additional example2* and keeping the original *example* for regression testing. Make it a practice to think twice before discarding any test case. Old test cases are one of the best ways to ensure that you haven't introduced unwanted changes to your code. Lest you fear having to retype or copy-and-paste test methods, notice that by merely over-typing the first line of a method and saving (compiling), you create a new method—different name, same code. Using this technique, you can effortlessly create a clone of the original and then proceed to modify the clone as much as you wish. Thus, you can retain the original until you consciously want to purge it.

## 8.7 A minor variation

Some people prefer a solution in which the account object itself builds new transactions and processes them, so that a test method contains expressions like:

account transactionAmount: -300 date: Date today.

<figure><img src="image_55.png" /></figure>

Prepare a test method in this spirit, then implement the variation by writing the instance method `transactionAmount:-date:` for class `Account`. This method will contain just one Smalltalk expression, and you need not write or modify any other methods.

## 8.8 "Private" methods

In Smalltalk's early days, a method was deemed *private* if it was to be invoked only by other methods in its same class (or subclasses); a method was *public* if it could be invoked by methods from other classes. Private methods were for use only by the programmer who was developing the class in question. Programmers working on other classes were not to invoke them. With this understanding, the owner of a class could rewrite it, revamping the class's private methods at will, as long as the public methods retained their names and functions.

In the last few years, many Smalltalk programmers have relaxed the interpretation of a private method. They now sanction invocations of a private method not only from the same class but also from closely cooperating classes. Privacy has evolved into an understanding within a subsystem or framework of classes rather than within an individual class.
In some Smalltalks you indicate that a method is private simply by adding the word "private" to the method's comment. Other Smalltalks have enhanced browsers that let you earmark a method as private, either by placing it in a special category or by means of a button that toggles between a list of all private selectors or all public selectors.

In all cases, though, designating a method private is only informational. Unlike a C++ compiler, the Smalltalk compiler has no way to determine whether a method your code invokes even exists, let alone whether it happens to be private. Therefore your code can freely invoke any method you like, private or not, even though the author of the method may have intended otherwise. In short, Smalltalk privacy is a recommendation only; it is not enforced.

* Browse through some Smalltalk classes and find some private methods.

* Which methods in your checking account solution ought to be marked private? Make them private by pulling down or popping up the *Methods* menu and selecting *Change public/private*.

## 8.9 Commentary: getters and setters

Simple methods like `getDate`, which merely return an instance variable, are called "getter" methods. Smalltalk stylists usually write getters more economically like this:

```
date
^date
```

This style is not ambiguous, in spite of how it may appear: the first *date* is the method selector and the second is the instance variable in the transaction object.

The opposite of a getter is a "setter," with a selector like `setDate:` or simply `date:`. The method would be written:

```
date: aDate
date := aDate
```

Getters and setters (together called *accessor methods*) are common, pedestrian methods in object-oriented programming, but take care not to overuse them. Writing a public getter and setter for every instance variable violates the spirit of encapsulation, because it announces that any other object may access the instance variables.

On the other hand, one stylistic school of thought recommends that you write private getters and setters for every instance variable. The object itself should access its own instance variables *only* by invoking the getter and setter methods, never directly. This convention makes the design less brittle. For example, imagine that you decide
later to move information that is now in an instance variable to an entirely different object. Without a getter and setter, every method that touches the instance variable breaks. With a getter and setter, only the getter and setter methods must be rewritten.

For a discussion of this and other Smalltalk coding conventions and their rationales, see [Skublics et al. 1996].

## 8.10 Summary

In the exercises of this chapter you produced a complete working application, however small or artificial. By this I mean that all the application logic is there, and it executes correctly. But you have probably noticed that the windows and buttons and scrollbars that people have come to expect of Smalltalk applications are absent. Your application has no user interface to speak of.

This absence is no accident. As you will see in Chapters 11–13, serious object-oriented developers work hard to separate their user interface code from their application logic. When we designed the checking account application in Chapter 7, we concentrated solely on the application objects, not a user interface. Windows come later.
CHAPTER 9

When (not) to inherit

Now that you have worked through serious Smalltalk code, we return to conceptual challenges. In Chapter 2 I suggested that aggregation and inheritance are independent, separable ideas. In fact, they are not so independent, and for some problems it is difficult to decide which of the two to apply. This chapter exposes the tension between them. (Further discussion appears in Chapter 14, on polymorphism, and in the commentary on page 255.)

## 9.1 Historical background

In recent years, inheritance has received much more attention than aggregation, mostly as a matter of fashion. Aggregation is the older facet of programming life. Programmers have used it for decades, so unwittingly that they never bothered to give it a glamorous name. In Pascal, an aggregation looks like this:

```pascal
type Flight = record
  gate: integer;
  terminal: char;
  onTime: boolean
end;
```

and in C, like this:

```c
struct Flight {
  int gate;
  char terminal;
  int onTime;
};
```
Both samples express the idea of composing an airline flight from three constituents. Of course, nowadays the flight and its constituents are all likely to be objects, but the underlying idea is still aggregation. In Smalltalk, one would have:

```
Object subclass: #Flight
    instanceVariableNames: 'gate terminal onTime'
    ...
```

Notice the disappearance of type information in the Smalltalk code fragment. This absence is not a characteristic of object-oriented programming in general, but of Smalltalk in particular. The C++ version looks much like the C version, including the type information, with the principal difference being the word *class* instead of the word *struct*.

## 9.2 Inverting hierarchies

With inheritance as well as aggregation in our vocabulary, the potential complexity of a design doubles. When a language gains power, it also presents opportunities for con- fusion. Consider this innocuous aggregation:

```
Face
|
Mouth
|
Tongue
```

I suggest that by inverting this aggregation, I can produce a legitimate inheritance hierarchy:

```
Tongue
|
Mouth
|
Face
```

Here's my argument. According to the discussion of inheritance in Chapter 2, we agreed to the rule of thumb that instances of a subclass have *more* properties than instances of their superclass. *Mouth*, then, should be a subclass or special kind of *Tongue*, because a mouth is a tongue embellished with teeth, gums, and lips. Even more striking, *Face* should be a subclass or special kind of *Mouth* because a face is a mouth plus lots of additional properties like eyes, nose, ears, and cheeks. A face even does everything a mouth does (it eats), and also sees and smells and hears. This analysis, preposterous as it sounds, is completely consistent with the definition of inheritance. Nothing in Smalltalk or C++ prevents you from designing and implementing a class hierarchy in this way.
Hence the dilemma: should these classes be designed using aggregation or inheritance? In this case, trust your intuition. Although it's entirely possible to use inheritance, thinking of Face as a special kind of Mouth just isn't intuitive. And what isn't intuitive to the designer is unlikely to be intuitive to other programmers who will use the design. The essence of programming objects is the cognitive economy they promise; a good design reduces mental translations. This observation alone justifies designing a tongue as part of a mouth and a mouth as part of a face.

But we are not ready to dismiss the example yet. The decision may not be so clear in other languages. Smalltalk supports *single inheritance*—each class has exactly one immediate superclass. Other languages, like C++, support *multiple inheritance*, where a class can inherit from several immediate superclasses. Designers using these languages sometimes employ a technique called *mix-ins*. Mix-ins are simple classes like *Mouth* and *Nose* that are used as superclasses for creating more complicated subclasses like *Face*. The subclass gets its properties and behavior by inheriting from as many mix-in superclasses as it needs. Thus, *Face* could inherit from *both* *Mouth* and *Nose*. Notice that although mix-ins clearly rely on the inheritance *mechanism*, the designer is *thinking* of composition or aggregation—building an aggregate object like a face from components like a mouth and nose.

## 9.3 Buy or inherit?

The problem in the previous section illustrates one of the most characteristic object-oriented design quandaries, that of *buying versus inheriting*. To *buy* an object is simply to acquire one for use, often by aggregation. *Buy* is a simple, evocative word, to my knowledge first used in the context of programming objects by Bertrand Meyer [Meyer 1988]. (You can also use the stuffier synonym, *compose*.)

In the preferred design above, class *Face* buys class *Mouth*. We implement this design in Smalltalk by defining an instance variable in the *Face* class that will refer to a *Mouth* object:

```object
Object subclass: #Face
    instanceVariableNames: 'mouth ...'
...
```

The method that initializes *Face* will include a statement like:
```ruby
mouth := Mouth new.
```

If, instead of buying a mouth we wish to inherit it, as in the less desirable design, we would have:

```ruby
Mouth subclass: #Face
...
```
These two designs represent the full range of options open to the designer. There are two techniques an object-oriented designer can use to access a class's behavior or properties: buy or inherit. If you like what you see in class Y and want to incorporate it into class X you must either buy from Y or inherit from Y; these are the only ways to give X direct access to Y. (Indirect relationships are another matter: see the discussions on many-to-many relationships on page 217 and lawyer objects on page 233.)

This is a bold claim, but it is entirely consistent with your experience. Every direct relationship you've designed or seen so far either buys or inherits. For example, in the checking account exercise in Chapters 7 and 8, the Account class bought a SortedCollection to use as its log.

## 9.4 Exercise

Remember that in Smalltalk, class Collection is an abstract class that is a superclass of many subclasses with container-like properties. One of these subclasses is OrderedCollection. An instance of OrderedCollection maintains its elements in relative positions: it has a first, second, ... and last element. It has methods that remove or add to either end of it. Thus, it resembles an array whose size may grow or shrink. For this exercise, we care most about the methods that stretch or contract from the far end, namely addLast: and removeLast.

* Design a Stack class. Because class OrderedCollection already offers stack-like properties, you will want to exploit OrderedCollection directly. Sketch a solution that buys, then a solution that inherits from OrderedCollection.

## 9.5 Solution and discussion

Here's a design for buying an ordered collection:

<figure><img src="image_56.png" /></figure>
The instance variable oc enables the stack to access the ordered collection it is buying. The essential methods for a stack are **push:** and **pop**. Their code buys an appropriate method from the ordered collection, simply by forwarding the request across the instance variable. Thus for pushing:

```
push: anObject
oc addLast: anObject
```

And for popping:

```
pop
oc isEmpty
    ifTrue: [ ^nil ].
oc removeLast
```

(The first statement prevents a walkback in case someone tries to pop from an empty stack.) Initialization sets up the instance variable to point to a valid ordered collection:

```
initialize
oc := OrderedCollection new
```

Contrast this with a design for inheriting instead of buying from class Ordered-Collection:

<figure><img src="image_57.png" /></figure>

Because we're not buying, there's no instance variable to forward requests across. And because we are inheriting, the stack inherits the **addLast:** and **removeLast** methods from its superclass. The stack is an ordered collection; that's what inheritance means. That's why the drawing shows only one object. The code for **push:** is therefore:

```
push: anObject
self addLast: anObject
```

The only difference from buying is that **self** receives the message instead of **oc**. In fact, **self** is the one and only object available for receiving messages.

The code for **pop** changes in the same small way. And the **initialize** method disappears, because there is no instance variable to set up.
## 9.6 Conclusions

Either technique, buying or inheriting, works. Inheritance generally yields a smaller solution. In the example, inheritance lets us dispense with the **initialize** method, as well as the `oc` instance variable. The net saving in this small example is only about two lines of code, but it still illustrates the general rule that inheritance saves code.

Another consequence of inheritance is *tight coupling*: inheritance couples the subclass to its superclass so tightly that absolutely everything that applies to the superclass also applies to the subclass. Whether this coupling is desirable or not depends on the situation.

In our example, *tight coupling* would be undesirable. It would imply that any of the dozens of messages that make sense for an ordered collection would also make sense for a stack. That's much more than we bargained for; it is treacherous for a stack to respond to *OrderedCollection* messages like `at`:put: or `removeFirst`. A trustworthy stack ought to respond only to messages `push:` and `pop`. Thus, to prevent subversive messages in Smalltalk, the designer must buy instead of inherit. That is what the first solution showed: buying safeguarded the stack from responding to *OrderedCollection* messages.

Inheriting, thereby tightly coupling two classes, is a long-term commitment, because as the software ages and undergoes maintenance and enhancements, any changes to the superclass will automatically reflect into the subclass. Again, whether this commitment is desirable or not depends on the situation. The designer must consider not only the economies of coupling the classes, but whether users of the classes expect them to evolve in tandem. Do they expect public methods added later in the superclass to be relevant for the subclass too?

In our example, it is unlikely that enhancements to the public protocol of *OrderedCollection* will ever matter for stacks. Stacks should *not* do much besides push and pop. Thus, subclassing *Stack* from *OrderedCollection* confers no maintenance benefit and may even deceive users of stacks into expecting more similarities with ordered collections than they should.

For this exercise on stacks, then, software engineering considerations militate in favor of buying. The modest code savings from inheriting *Stack* from *OrderedCollection* aren't worth the reliability and maintenance implications.

The buy versus inherit decision is a fundamental activity in object-oriented design. Initial intuition is often valid, but you should weigh the trade-offs—(1) code reduction, (2) subversive superclass messages, and (3) maintenance—summarized in this table:
<table><thead><tr><th></th><th>Buying<br>(Selectively access<br>methods of<br>another class)</th><th>Inheriting<br>(Access all methods<br>and instance variables<br>of another class)</th></tr></thead><tbody><tr><td>Code bulk</td><td>More</td><td>Less (good!)</td></tr><tr><td>Subversive superclass<br>messages</td><td>Preventable (good!)</td><td>Possible</td></tr><tr><td>Maintenance</td><td>Evolve independently<br>(loose coupling)</td><td>Evolve together<br>(tight coupling)</td></tr><tr><td>Familiarity with<br>the superclass's internals</td><td>Less</td><td>More</td></tr></tbody></table>

The last row in the table indicates the degree to which the developer will have to study a class before buying or inheriting from it. Buying requires less familiarity with the internals than inheriting does. For this reason, buying is sometimes known as *black-box reuse* and inheriting is sometimes known as *white-box reuse*.

The table is not the last word on the buy versus inherit dilemma. We will discuss a powerful reason to inherit—*polymorphism*—in Chapter 14. Also, the commentary on page 255 summarizes buy or inherit decisions in the context of object-oriented frameworks.

The situation in other object-oriented languages is not as clear as the table suggests. C++ designers use inheritance more than Smalltalk designers do, partly because it is their only means of expressing polymorphism, but also because the C++ language has facilities that can limit the wholesale inheritance of superclass features. Because Smalltalk has no such facilities, Smalltalk designers must heed the cautions above.

If in doubt, consider buying. Novice designers tend to overuse inheritance; experienced ones make an effort to buy. As a rule of thumb, buying is less brittle than inheriting.

## 9.7 Commentary: multiple inheritance

Multiple inheritance (page 99) is a powerful facility of some object-oriented languages. What do you do if your language (Smalltalk) doesn't support it? According to the principle spelled out in this chapter, only one choice remains: buy. If X and Y are two classes from which you would like a class C to multiply inherit, and Smalltalk limits you to singly inheriting from just one of them, then you will have to buy from the other.
The difficulty is that you may really want to inherit from both X and Y. That is, you may really want C to behave as though it were both an X and a Y, which means that C should respond automatically to all the same messages that X and Y do. Inheritance has this automatic property. But buying doesn't. In this situation buying is therefore a poor substitute. Smalltalk is not adept at simulating multiple inheritance to the degree that would satisfy a C++ programmer.<fnref n="1" />

The argument over multiple inheritance isn't completely one-sided. Its detractors argue that it leads to problems that require complicated linguistic rules to resolve, and these unfortunate problems occur so commonly as to counterbalance its benefit. Here is a simple illustration of a problem known as *repeated inheritance*, so called because a class will inherit more than once from another class.

Certain television programs mix dramatizations of historical matter with archival documentary footage to produce *docudramas*. A multiple inheritance hierarchy for this situation is shown on the right.

Consider an instance variable defined in class TVShow for the show's director. Classes Drama and Documentary evidently inherit this instance variable. Class DocuDrama thus stands to inherit two directors, one from each of its superclasses, which would be an artistic nightmare. We would prefer that DocuDrama inherit just one director instance variable.

<figure><img src="image_58.png" /></figure>

On the other hand, consider another TVShow instance variable, *duration*. Classes Drama and Documentary again inherit this instance variable, but now we may prefer that DocuDrama inherit two copies of the instance variable, so that it can separately capture the minutes of dramatic material and the minutes of documentary material.

To attempt to accommodate either possibility—sharing some multiply inherited instance variables and replicating others—languages that support multiple inheritance introduce additional, complicating facilities. For the details, see C++'s *virtual base classes* [Stroustrup 1991] and Eiffel's *renaming* [Meyer 1992]. In short, multiple inheritance adds power to a programming language, but at a cost of complexity.

Here is a closing historical curiosity: multiple inheritance appeared briefly in Smalltalk-80, but was withdrawn because the benefits were deemed insufficient to compensate for the ensuing complications.

<footnote n="1">¹ Buying may not substitute for inheritance, but what about the converse: can inheritance substitute for buying? Rarely in Smalltalk, because of the reasons discussed in Section 9.6. It turns out though that C++ supports a form of inheritance called *private inheritance* that resembles buying much more than Smalltalk's inheritance does.</footnote>
CHAPTER 10

## Use cases and dynamic relationships

Until now, we've concentrated on the static relationships in an object-oriented application—aggregation, inheritance, the methods and instance variables of an object, and the like. The dynamic relationships—the order in which methods execute, the births and deaths of objects and their interactions during their lives—are just as crucial for understanding a design. These are the relationships that weave the objects together to actually do something. Without them, an object model (or object analysis or object design) is as empty as a ghost town.

Long before the dawn of objects, software engineers knew that dynamic relationships were important. They used diagrams they called "flowcharts" to represent the idea. Two decades of object-oriented programming passed before anyone thought to introduce the same idea into an object-oriented design method. (See the historical commentary on page 114.) Nowadays, finally, dynamic relationships are a standard feature of all the major object-oriented design methods.

### 10.1 Interaction diagrams

A *use case*, as coined by Ivar Jacobson, is a scenario involving a user and an application. In his words, it's "a behaviorally related sequence of transactions in a dialogue with the system" [Jacobson et al. 1992]. Now, this definition may make sense to a computer scientist, but it's a little esoteric for non-technical people. And non-technical end users are usually the people who are supposed to help us understand new problems by describing their use cases. Therefore I like to use a more accessible definition, like "an
activity or task that the computer can help the user perform." This wording is simple enough that it won't stand in the way of a meaningful dialogue between computer professionals and computer users.

An example of a use case is, "Ask an Automated Teller Machine for the balance in an account." A detailed rendition of this use case might be, "The customer inserts his card, the machine prompts him for a PIN...." Textual descriptions like these can be cumbersome or vague, so the designer may choose to sketch an *interaction diagram* like this:

<figure><img src="image_59.png" /></figure>

Each vertical line represents an object (labeled at the top of the line). Horizontal solid arrows represent messages and dashed arrows depict the object that a method returns. The vertical boxes illustrate the duration of each method. Notice the *time* dimension. That is what differentiates these interaction diagrams from pictures of class hierarchies and aggregation relationships.

Interaction diagrams illuminate dynamic behavior better than any static picture can hope to do, just as flowcharts and dataflow diagrams did for earlier, pre-object-oriented methodologies. As a rule, whenever a design seems fuzzy in your mind, pause (don't write code) and examine its dynamic structure with use cases and interaction diagrams.

*Concurrency warning:* Nothing is concurrent about these interaction diagrams, nor is object-orientation inherently concurrent. In particular, nothing in the Smalltalk and C++ languages has anything to do with concurrency. This news comes as a surprise to many newcomers, because the terminology of objects emphasizes *messages*, a word that conjures up numerous senders and receivers communicating simultaneously. Concurrency is possible in Smalltalk and C++ as well as most other languages, but not because
the languages support it directly. Instead, you have to go outside the language by calling operating system services. For example, you can use UNIX forks and semaphores or create OS/2 threads from either C++ or Smalltalk.<fnref n="1" />

In interaction diagrams like the one above, what may appear to be concurrently executing threads or processes (like the vertical bars for *query balance* and *get balance*) only indicate ordinary call-return semantics. The sending operation (*query balance*) blocks (does not proceed) until the message it sends (*get balance*) returns, just as a calling procedure in a conventional programming language blocks until a subprocedure it calls returns.

Sometimes an activity of the system under study is at such a low level and so far from the user that you would be hard pressed to describe the activity as a use case. But interaction diagrams can still be illuminating. The following example emphasizes low-level Smalltalk message flows; the user's role is only a mouse click. The diagram tracks what happens from the time Smalltalk starts looking for an event, through converting this raw operating system information into an actual Smalltalk message, and finally scheduling this message for subsequent execution by placing it in the *CurrentEvents* container.

<figure><img src="image_60.png" /></figure>

<footnote n="1">¹ Although Smalltalk has classes for processes and semaphores, their instances *simulate* concurrency and are not necessarily related to concurrent behavior in the underlying operating system. Future releases from Smalltalk vendors may associate Smalltalk's concurrent objects with actual operating system threads. Java and Ada95 are commercial object-oriented languages that have built-in concurrency features.</footnote>
Messages to self are depicted by solid arrows that hook back to the object they come from. Dashed, hooked arrows depict the objects returned from such methods. When successive return values are the same, the returned object isn't repeated each time: for example, the last four return values are all the nil object, even though the two hooked arrows aren't labeled. Sometimes a return value—frequently the default return value of self—is unused and uninteresting; then the dashed arrow is omitted entirely, as you can see for the add: method that finally schedules the Smalltalk message w b1Up: aPt. There's no standard notation for these diagrams; I often use the conventions above, but use whatever works for you.

This scenario applies to a specific Smalltalk (Smalltalk/V) and a specific operating system (OS/2) and window manager (Presentation Manager, or PM). Several of us who were concerned with event handling in that environment used this diagram off and on for years as a reference.<fnref n="2" /> The diagram is most likely not relevant for your problems, so you should not study its details. But other use cases and interaction diagrams of complex scenarios specific to your own problem domain will be valuable to your development team. Even a rough hand-drawn sketch is worth the effort. (See the examples in the analysis and design discussion that begins on page 110.) Try to retain some form of your sketches, no matter how rudimentary. Not only will other developers appreciate them, but you will discover that testers find use cases and interaction diagrams more useful than inheritance and aggregation diagrams. Testers test what software *does*, not the static relationships between classes and objects.

## 10.2 Exercise

In Chapters 7 and 8, you added transactions to a log (an instance of class SortedCollection), and with no more support than a <= method for class Transaction, the log sorted the transactions chronologically. For many students, this is a mysterious happening.

* Work through a simple scenario until you are comfortable with the object interactions. You can sketch an interaction diagram for the scenario, but you may find that anthropomorphizing the objects—representing them as people or pencils or coins— is just as effective. If you sketch an interaction diagram, keep in mind that the value of the exercise is in thinking it through, more than in producing a pretty picture.

<footnote n="2">² The event happens to be number 114, which the operating system has defined as an up-click of the left mouse button, and the resulting Smalltalk message (w b1Up: aPoint) is a message to the window telling it that the click occurred at a specific point in the window. Another scenario, not illustrated here, iterates through the CurrentEvents container and executes each of the messages therein.</footnote>
10.3 Solution and discussion

Before you examine the interaction diagram below, it's important to develop a sound intuition for the objects and their static relationships. That's because interaction dia- grams, sadly, contain nothing to help you reconstruct that static information. Let's review this static information. Refer to the drawings on pages 85 and 86 for this review.

The log, being an instance of SortedCollection, by default uses the comparison `<=
` to sort. When we add a new transaction to it, it will ask the transaction to compare
itself (using `<=`) to the transactions already present, one at a time, until it finds the
right position in which to insert the new transaction. What does this new transaction
use to compare itself with the other transactions? It uses its own date, comparing it
with the other transaction's date. This is a key piece of static information—that the
dates are encapsulated within the transactions. Keep in mind that the log contains
transactions, that each transaction encapsulates its own date, and that transactions
have a `getDate` getter (often named simply `date`) to access this encapsulated date. All
this information is static. The interaction diagram that weaves this information
together is:

<figure><img src="image_61.png" /></figure>

Note that two instances of Transaction appear in the diagram. We need at least that
many to illustrate a comparison. Also note that although trans2's date `date2` partici-
pates critically in the interaction, at this level of detail we cannot see it receive or ini-
tiate any messages.
## 10.4 Use cases and interaction diagrams in analysis and design

Use cases are valuable in the early stages of analyzing a new problem. Here are two examples.

1. To build a subsystem for a new pharmacy application, we asked users of the old application to think about the tasks they wanted the computer to help them with. They first listed about four tasks, such as "enter a drug order" and "dispense drugs." These are both use cases. Because they had already used CRC cards to identify a number of objects, we began next to work through interaction diagrams. Not unexpectedly, they observed that there were some important variations to the initial use cases. We identified those as additional use cases. When we had completed this preliminary inquiry, they had found about eight use cases for the subsystem in question, and we all had a good idea of the main objects and their interactions. Together with the CRC cards, we had the information we needed to develop a crude mockup of the subsystem.

2. In the requirements analysis for a banking application, although we had iteratively developed important CRC cards and use cases, not until we worked through an interaction diagram for a use case did the software developers and bankers reach a real understanding. The bankers recognized for the first time how objects they conceptualized could really do work for them by sending messages to one another, and the developers saw both what the bankers were really thinking and how we had to design the software to solve their problem. For both parties, this was a cahartic moment.

These experiences illustrate one technique for object-oriented analysis. The first two steps (their order is not critical) are to elicit CRC cards and use cases from the users. Then, by working through message flows, the developers and users together can refine both the CRC cards and the use cases to produce an initial round of object-oriented requirements. The entire discussion can occur without introducing any technical complications—no one has to use words such as class, inheritance, or polymorphism. Everyone can communicate using cards (objects), activities (use cases), and telegrams or messages (interaction diagrams).

A general aside about analysis: Good analysts are flexible, spontaneous people. They need to be able to switch gears when they sense that users are getting frustrated. The larger the group of users, the worse the problem. Different people think in different modes, and get frustrated for different reasons. Adapting to this variability in human cognition is at the heart of successful analysis. A technique that inspires one person stifles another. And a technique that works on one aspect of a problem won't
on another. In the banking application above, after many successful sessions with objects and scenarios, one murky area remained. The banker charged with helping us developers understand it was as frustrated as we were. So we stopped talking about objects entirely, and started to sketch window layouts and how they might relate to one another. This shift produced such responses as, "No, not that way.... Yes, yes, good!" that got the whole effort moving again. Of course, developers imagine objects under windows, and we were therefore subconsciously gathering object-oriented requirements, but the conversation had been unshackled from any object baggage, much to everyone's benefit.

I don't mean to suggest that drawing windows is a universal remedy for analysis gridlock. It happened to work for those people on that aspect of that problem. That is the point. Different approaches will work for different people and problems. The successful analyst needs the creativity and optimism to keep trying approaches until one works for the situation at hand. Methodologies won't help.

It is worth repeating that it is possible to spend too much time documenting message flows with interaction diagrams. Not every message flow deserves the time it takes to make it pretty on a computer:

<figure><img src="image_62.png" /></figure>

Real analysis sessions are so harried that we must capture message flows by hand—computers are too slow for the dynamics of creative human interaction. Sometimes we do not even have the luxury of thinking through the *objects* that send and receive messages. We may be pleased to walk out of a session with precious scribblings from a whiteboard that resemble:
<figure><img src="image_63.png" /></figure>

Hastily hand-drawn flows like this are not very readable or shareable. On the other hand, transcribing diagrams to a computer can take more time than your schedules allow. Moreover, for many diagrams the chief benefit comes through the human exchange in which they were created, rather than from the appearance of the final art-work. You will have to decide, after considering the usual factors—shareability, project standards, available staffing, management expectations—just how many sketches are worth the considerable expense of transcribing into attractive computerized form.

## 10.5 Limitations

Interaction diagrams have limitations which may frustrate or disappoint you if you expect too much from them.

* Interaction diagrams cannot represent loops and conditionals. You must either limit your diagram to a scenario having a single path or annotate the diagram informally with text. The single-path assumption is often acceptable because it is mainline processing that you're often trying to illuminate. Another way to produce non-branching diagrams is to decompose a highly branching diagram into many small non-branching ones; these small diagrams turn out to be reusable units for reassembling other complicated diagrams.

* Not everything is a message. For a Smalltalk designer, assignment is the main culprit. Interaction diagrams represent messages between objects nicely, but that's all. An assignment isn't a message to an object, and thus doesn't lend itself to interaction
diagramming. (Try diagramming balance := 2500.) For a C++ designer, the situation is even worse: ordinary function calls, which lack a preferred receiver object, aren't messages either. You can't express them in interaction diagrams, which require well-defined sending and receiving objects.

* Interaction diagrams are graphical, but they aren't memorable. Because they constrain the objects to appear in just one dimension across the top edge, they lose the spatial benefit of placing objects above, below, or near or far from each other, with connecting lines indicating, say, aggregation relationships. In other words, interaction diagrams express time wonderfully, but are virtually devoid of static information.

The first two limitations are troublesome mostly in lower-level interaction diagrams. If you stay at a high enough level, like the first example in this chapter, the account balance query, you can often avoid these limitations.

## 10.6 Summary

I think of the design of a complex application as a misshapen multidimensional blob. There is no simple formula for describing or understanding the blob; all one can do is slice it in different ways and examine the cross-sections to get an idea of its structure. The most familiar slices are static; they are usually class diagrams that show responsibilities, plus inheritance and aggregation and other relationships.

But a static slice tells you nothing about what the application is supposed to do for its users. For that you need dynamic slices. The simplest dynamic slice is a one-sentence use case, then comes an expansion of the use case into a sequence of statements, and finally we have interaction diagrams with their objects and messages. These slices describe the functionality of the application.

Early in analysis and design, the dynamic slices clarify the static slices. That's because as you work through dynamic slices you realize that your CRC cards or class diagrams are missing various objects and responsibilities. Later, when the blob has settled down a bit, the dynamic slices become test cases for system testers: if a use case or interaction diagram doesn't work as documented, the tester knows something has gone wrong. (Static diagrams are almost useless for system or integration testers, again because they say nothing about what the application ought to be tested for.)

When you think about something from a different perspective you usually learn something worthwhile. Thinking through the dynamic dimension usually illuminates murky areas of the blob. If a design problem stumps you, try outlining a use case or an interaction diagram; at the very least this tactic will give you a fresh outlook on the problem. Often, it will propel you into a clarification of a murky area.
Unfortunately, for a lot of blobs not a scrap of documentation exists, yet they have somehow gotten themselves realized into Smalltalk. Sooner or later you will need to understand one of these blobs. The only surviving artifact is code, so you have no choice but to slice through it. You can slice statically, by drilling down through method invocations with browsers (using Browse Messages > Implementors, again and again). Eventually, you will also have to slice dynamically, setting up experimental conditions and stepping through execution paths with the debugger. This procedure is like skillfully examining specimens with a microscope: instead of selecting tissue slices and preparing them with appropriate dyes, you scaffold appropriate objects together and set up conditions for a good debugger session. In effect you are recon-structing what interaction diagrams would have told you had there been any.

## 10.7 Commentary: historical note

The value of understanding the dynamic aspect of a problem was appreciated long before objects became popular. Software engineers used flowcharts and hardware engi-neers used timing diagrams. What is surprising, or embarrassing, is how long it took for an object-based variation to appear. Jacobson first alluded to use cases in [Jacobson 1987]. By now, every mainstream object-oriented design method advocates some technique for representing an application's dynamics. These techniques go by assorted names: interaction diagrams, message flow diagrams, event traces [Rumbaugh et al. 1991], timing diagrams [Booch 1994], scenarios [Reenskaug 1996], or scripts [Gibson 1990; Rubin and Goldberg 1992].

For a different, higher-level look at application dynamics, see timethreads in [Buhr and Casselman 1992].
CHAPTER 11

The venerable model-view-controller

An application’s or system’s user interface (UI) consists of everything the user interacts with—the screens and sounds, menus, keyboard and mouse, and so on. This chapter begins the discussion of user interfaces; the discussion concludes with Chapter 13, which addresses the substantial challenges in actually designing a satisfactory user interface.

We are going to set a goal: to separate UI from non-UI software elements as prac- tically as we can. The idea of this separation, known as the model-view-controller (MVC), dates back to the late 1970s and is the most important milestone in the his- tory of object-oriented user interface design.

11.1 Model-view-controller example

Imagine that someone needs a computerized counting tool. Here are two applications that would do the trick:

<figure><img src="image_64.png" /></figure>
These two applications evidently display their values differently, one digitally and the other like an analog clock. The two kinds of displays are known as two kinds of *views*. Strictly speaking, a *view* is just a way of displaying information. At this moment, the digital view displays 9 and the analog one displays 3.

There are no connections between the two applications, even though they appear side by side on the screen. You can increment either independently of the other, by means of their respective menus. The applications therefore each rely on their own underlying counter object—an object with an increment and decrement method and an instance variable representing the current value:

<figure><img src="image_65.png" /></figure>

These two instances of *counter*, known as *model* objects, operate independently of each other, just as the views above operate independently. A model is responsible for changing and maintaining the state of the underlying application—in this case, the underlying counter. Models are ignorant of how their information is displayed; that is, they are ignorant of their views. Models aren't visible on the computer's display.

We'll discuss the mechanism that connects views to their models shortly, but first consider another possible configuration: both views could share one model object. The two views would then operate in lockstep: if you increment either, the other also increments because it is merely another view of one and the same model object. Here are the two views:

<figure><img src="image_66.png" /></figure>
And here is the model object both share:

<figure><img src="image_67.png" /></figure>

So far, all the counters we've considered still operate in the same way, by means of menu selections. The next step is to introduce an entirely different input mechanism, like the buttons here:

<figure><img src="image_68.png" /></figure>

This application has the same kind of digital view we've already seen, and also the same kind of model as before, but a different kind of *controller*—the technical term for the input mechanism. This kind of controller also could have been associated with the analog view, producing this counter application:

<figure><img src="image_69.png" /></figure>

In theory then, we can decompose the design of an application into independent elements—models, views, and controllers. In practice, such a decomposition may be more or less feasible depending on the framework of classes in which you are compelled to work. For example, we shall see later that a full three-way decomposition is more likely to occur in VisualWorks than in other Smalltalk environments.
You can think of a controller as an object that handles input events and a view as an object that handles output events. More precisely, a controller handles events that the user generates, like pressing a mouse button, and a view handles events that the model generates, like increasing the value of a counter. A view provides a *look* and a controller provides a *feel*. The model underlies the views and controllers, and as we will see in the next section, the ideal model is independent of views or controllers. The model neither knows nor cares about any of them.

## 11.2 Exercise

The screen below displays several counter applications. The top two counters are simple ones that operate by mouse clicks: a left click increments the count and a right click decrements it.

<figure><img src="image_70.png" /></figure>

* How many *kinds* of models are there?

* How many *kinds* of views?

* How many *kinds* of controllers?

* How many *instances* of models?
## 11.3 How MVC works

Here is how the user interacts with an application based on an MVC decomposition:

<figure><img src="image_71.png" /></figure>

The view objects render information to the user and the controller objects accept the user's input. The user has no direct contact with model objects; she imagines their presence and characteristics only from her interactions with the views and controllers. (How and what she imagines are the subjects of Chapter 13.)

In classical MVC, the relations among these three kinds of objects are indicated here:

<figure><img src="image_72.png" /></figure>

You can see that views and controllers have instance variables that refer to their model as well as each other. They know their model. But the converse is false. The model does not have explicit instance variables pointing to its views or controllers. This is a crucial omission. The underlying application should function without knowledge of how the user interface happens to display information or interpret input. The application should not know or care what kind of view or controller happens to be attached to it,
nor even whether several views and controllers may be attached, or different ones as time passes. The essence of MVC is this radical decoupling of the model from the user interface components.

If the model has no instance variables referring to its views and controllers, how does it inform them of changes in its state? In other words, how can the model proclaim ignorance of views and controllers, yet still inform them of changes? The answer is that it informs them indirectly, via a concealed relationship known as *dependency*: the model's dependents are indicated above by dashed arrows. Whenever the model sustains a change that it wants to convey to its dependents, it sends a message to itself—**self broadcast**<fnref n="1" />—which eventually causes a message to be sent to each of its dependents—**dependent update**. The dependents decide what they want to do, if anything, to update themselves; that is the function of the **update** methods above. In the counter example, the view's **update** method would send a message to its model to fetch the current value of the counter, with which the view could refresh its display.

Roughly speaking, there are two mechanisms for implementing dependency relationships. One uses a global dictionary, where the keys are models, and the value associated with each key (model) is a collection of the model's dependents. The **broadcast** method searches the dictionary for the model in question, then sends the **update** message to each of the objects associated with the model. The upcoming exercise illustrates this mechanism.

The second mechanism gives each model object its own **dependents** instance variable that refers to an ordered collection of its dependent objects. The **broadcast** method then sends the **update** message to each object in this collection. You don't want to write code for dependency and broadcasting every time you construct a new class of models, so if you adopt this second mechanism you should write the code you need once in an abstract class called **Model**, and subclass all your model classes from it. This technique conceals the relationship just as we wanted; application programmers who build model objects don't have to know that the **dependents** instance variable is present.

A refinement of the second mechanism offers a sharper form of broadcast, in which a cluster of messages is broadcast in response to a given event. This form is now available in all the major Smalltalk dialects (see the table on page 125). For example, in VisualAge the class **AbtObservableObject** does entirely away with the simple **dependents** instance variable; instead it has an instance variable called **eventDependents** that is a dictionary-like object whose keys are events and whose values are clusters of messages. Therefore, instead of a fixed broadcast resulting in the same **update** message

<footnote n="1">¹ This message is **self changed** instead of **self broadcast** in some dialects.</footnote>
being sent to every object, an AbtObservableObject can selectively broadcast the clus- ter of messages associated with any one of its events. And these messages may have any names or receivers at all. In effect, broadcasting can be surgically precise.

This sharper form of broadcast is sometimes called event notification . Event notifi- cation is increasingly popular and may eventually displace the older, more basic forms of broadcast.

11.4 Exercise: the original dependency mechanism

口 All major Smalltalk dialects support a general dependency mechanism that lets any object depend on any other. In most Smalltalks, this mechanism uses a class vari- able of Object named Dependents . Inspect Dependents . What kind of object is it, and what does it currently contain?

口 Execute:

X := Penguin new. "Any object will do!" X addDependent: 17. X addDependent: 12. Dependents inspect.

What does Dependents contain now?

口 Next execute:

X broadcast: #update.

Smalltalk broadcasts an update, but you should see nothing. That’s because inte- gers don’t respond to update . Now write an update in Integer whose body is:

Transcript cr; show: 'I am ', self printString.

(The Professional version of IBM Smalltalk may require you to put the method into a new application edition. Any edition, including a "scratch" edition, suf- fices.) Again try:

X broadcast: #update.

This general dependency mechanism is serviceable, but by object-oriented stan- dards it is not well encapsulated. After all, any object can access the class variable Dependents in class Object . If you want to use a dependency mechanism, con- sider building or reusing one in which an object encapsulates its own dependents. The major Smalltalk dialects all come with such a mechanism. (See the table on page 125.)
## 11.5 MVC: benefits and difficulties

A clean MVC decomposition keeps the designer honest. It forces him to separate concerns, which is a basic goal of software engineering. He can focus on the coherence of the underlying model (more on this subject in Chapter 13) without worrying about presenting it on the screen. Conversely, he can invent new ways of presenting the model without having to reprogram the model objects. In short, development of the user interface and the model can proceed separately. The objects will then be smaller and less complicated and the prospects for reusing them will be better.

MVC also provides a pathway for porting an application from one platform to another: model objects should port with little or no trouble—good models are not cluttered with platform-specific code. The porting problem therefore reduces to rewriting only the UI code. The benefit depends on the relative proportions of UI and model code in the application. For the counter example above, with its simple model, the benefit is almost negligible. But for an application like a network simulation with rich algorithmic content, the benefit is considerable. In any case, ideally, the programmer responsible for the port will not need to know or learn anything about the underlying application or problem.

Desirable though it may be, a pure MVC separation is a lofty goal. Here are some difficulties.

* *Simple rendering.* In MVC, we strive to keep model objects ignorant of anything having to do with their presentation. Strictly speaking, it would be unfaithful to MVC to taint a circle object with a method that paints a circular arrangement of pixels on a graphical window, or even a method that spells out the characters 'Circle'. Similarly, a purist may challenge a method (such as we will see in the next chapter) for a checking account transaction object that returns a string detailing its date and amount. Such methods have to do with views, not models, the argument goes. If you insist on not tainting model objects with these rendering methods, however, you will have to pay the price for another layer of objects that are responsible for rendering. That can be an overblown response to relatively minor MVC infractions.

* *Validity and constraint checking.* In a screen in which the user enters, say, a telephone number, the UI has an opportunity to validate that the number's structure—country code, area or city code, number, and extension—is acceptable. The UI could even refresh another field, perhaps the name of the country. The more business-specific knowledge the UI brings to bear on such checking—which countries are acceptable, whether to allow letters as well as numbers for the phone number, and the like—the less pure the MVC decomposition becomes. The penalty for making the UI more powerful in these ways is that as the business evolves, UI logic as well as model code must be rewritten.
* *Partial refresh.* In classic MVC, the UI informs the model of specific changes, and the model then broadcasts a generic update back to the UI. For a drawing application, the UI would update by fetching *all* picture elements from the model, blanking the canvas, then refreshing the whole canvas. But if the specific changes affect only a small portion of the canvas, blanking and refreshing the whole canvas would be both slow and distracting. Classic MVC is not flexible enough to refresh just the small, affected portion; this localized refresh requires closer cooperation between view and model. The view still informs the model of the changes, but it must selectively fetch just those elements it needs from the model, and refresh just the altered portion of the canvas. This optimization does not relieve the model from having to broadcast—there may be other views, after all—but the current, active view should ignore the broadcast, lest it respond by blanking and completely refreshing itself, which is what we've been trying to avoid.

* *Drag and drop.* When the user drags an icon across the screen, the icon may change its appearance as it moves over different targets. For example, when a drop would be illegal many UIs change the icon to a "Do not enter" symbol. The legality of a drop commonly depends on a simple consideration, like whether the graphical element being dragged lies over a particular window. But the legality could conceivably depend on more complex considerations, such as the states of the underlying objects. A prescription icon may not be dropped on a patient icon if the patient is allergic to that drug; a letter may not be dropped on a mailbox if the letter has no addressee; an insurance policy may not be dropped on a client if the client is an assigned risk; and so on. In these situations the underlying model objects must participate in the negotiation, because only they know the relevant state information. Icon objects, which are merely visual artifacts, aren't smart enough to help; they do not even know what questions they ought to ask the model objects. MVC, with its broadcast metaphor, has no bearing on this fine-grained, real-time problem. A solution to this problem is to use *lawyer* objects (page 233). A lawyer knows both an icon and an underlying model object, and it negotiates with other lawyers that represent other icon and model object pairs. The UI maintains a collection of lawyers, one for each icon, and the lawyers decide whether one icon may be dropped on another, by negotiating between the model objects they represent.

The last three difficulties underscore the lesson that broadcasting is sometimes too slow and heavyweight. Users of today's computing systems expect immediate feedback; they cannot wait for the model to issue a generalized broadcast to the view objects. Instead, the view objects must become more intimately involved with model objects than they would be in an ideal MVC partitioning. MVC is not sufficient for every situation.
## 11.6 What's become of MVC?

The MVC idea originated in 1978-1979 during Trygve Reenskaug's visit to the Xerox PARC Smalltalk team, which formalized it in the Smalltalk-80 product, later to become VisualWorks.<fnref n="2" /> Digitalk carried essentially the same ideas into its early DOS Smalltalk/V products, where it was renamed to MPD (model-pane-dispatcher).

Nowadays, controller objects are commonly absorbed into view objects, so that the classical MVC(thirsteful reduces to a twosome. To see the rationale, think about the pushbutton controllers in the counter applications above. These controllers have view-like characteristics: the buttons are visible and they appear to bounce down and up when the mouse is clicked over them. A button controller is, in effect, already bound to a view-like object, and messages flow back and forth between the controller half and the view half to coordinate their behavior. Because controllers often have both view and controller characteristics, object-oriented UI classes usually coalesce views and controllers into one kind of object, which relieves the programmer of the burden of managing communication between two different objects.

Another reason for coalescing views and controllers is that unified view-controllers are a natural match for the built-in user interface "objects" (scrollbars, buttons, menus, and so on) found in native windowing environments such as X-Windows, OS/2 Presentation Manager, Windows, and Macintosh. It is simpler for a layer of programming objects above the windowing environment to mirror the underlying architecture than to dismantle it into separate view and controller constituents that aren't there to begin with.

These modern view-controller objects still go by the name *view*, or occasionally *interactor*. Instead of a classic three-way MVC decomposition, we decompose applications into this simpler MV form:

<figure><img src="image_73.png" /></figure>

<footnote n="2">² Trygve's account of the early history appears in [Reenskaug 1996].</footnote>
In short, coalescing views and controllers simplifies the programmer's task, at the cost of some loss of flexibility in mixing and matching looks and feels. Today, almost all UI frameworks, whether based on Smalltalk or C++, coalesce controllers and views. Examples include MacApp, Smalltalk/V, Interviews, and the X/Motif widgets used in IBM Smalltalk. VisualWorks is the most notable product that sustains full MVC separation.

From now on we will focus on MV separations instead of MVC separations. Thus the primary software engineering obligation of UI developers is to separate models and views. You should strive to avoid excess seepage of model behavior into views. Powerful GUI (graphical user interface) builders increase the temptation, because developers sometimes become so enamored of GUI building that they overlook the design of a coherent layer of model objects.

As I implied on page 120, several broadcast or dependency mechanisms are suitable for achieving MV or MVC separations. This table illustrates the variety available in the major Smalltalk dialects:

<table><thead><tr><th></th><th>VisualAge<br>(IBM Smalltalk)</th><th>Visual Smalltalk<br>(Smalltalk/V)</th><th>VisualWorks<br>(Smalltalk-80)</th></tr></thead><tbody><tr><th scope="row">Abstract View and<br>Controller classes<br>(supports full MVC)</th><td>No</td><td>No</td><td>Yes</td></tr><tr><th scope="row">Dependency supported<br>by a class variable<br>in Object</th><td>Dependents</td><td>EventHandlers<br>(Dependents in<br>older versions)</td><td>Dependents</td></tr><tr><th scope="row">Dependency supported<br>by an instance variable<br>in an abstract class</th><td>AbtObservableObject<br>broadcasts message<br>clusters<sup>a</sup> (aka event<br>notification)</td><td>EventManager<br>broadcasts message<br>clusters (aka event<br>notification)</td><td>Model broadcasts<br>message(s) like<br>update to all<br>dependents<sup>b</sup></td></tr></tbody></table>

The class variable in Object is convenient for quick and dirty broadcasts but should generally be avoided, because it is accessible from any object. It is therefore tantamount to a global variable, which we know to be generally undesirable. This mechanism also

<footnote>a As of version 3.0, instances of subclasses other than AbtObservableObject can also broadcast message clusters. The protocol is the same as the one in AbtObservableObject, but the methods are reimplemented in Object, using the auxiliary class AbtCLDTAdditions.</footnote>

<footnote>b ParcPlace-Digitalkintends to make EventManager the foundation for its instance-based broadcast protocol in its combined VisualSmalltalk/VisualWorks offering.</footnote>
involves more message sends, which could degrade performance in designs with many (probably too many) broadcasts. Thus you should try to use the built-in instance-based support (from the last row of the table), or build an abstract class of your own once, and subclass from it.

Because of the many workable approaches to broadcasting, it is unlikely that the ANSI standardization committee will specify a broadcast or dependency protocol as part of the forthcoming Smalltalk standard.
CHAPTER 12

Building windows

This chapter deals with building windows in the IBM Smalltalk environment. You are going to build windows from scratch—almost—with only a little help from a simple abstract class. This will be an excursion into the heart of user interface programming. The specific classes and methods in this chapter apply only to IBM Smalltalk, not other dialects. Windowing frameworks differ so widely between Smalltalk dialects that you will have little hope of reinterpreting this material for other dialects.

Using the techniques in this chapter to handcraft complicated windows would be inefficient. For constructing lots of intricate windows, programmers nowadays mostly use a GUI (graphical user interface) builder such as VisualAge or WindowBuilder Pro (for IBM Smalltalk) or VisualWorks (for Smalltalk-80). These have the advantage of simplifying the tedious aspects of window construction, although some also obscure the layer of window components where the programmer may want to fine-tune the behavior of the user interface. This layer is the subject of this chapter and, GUI builder or not, it is desirable to know a little about it.

Before you can build a first, simple window in IBM Smalltalk, you must learn a little about Motif. Motif is a standard programming interface for building GUIs. It was developed by the Open Software Foundation (OSF), a consortium of large com- puting companies. Motif is not an object-oriented programming system; it consists instead of many conventional functions.

IBM Smalltalk’s user interface components include a layer of classes and methods whose names and arguments mimic Motif reasonably well. These classes therefore have a strong affinity with systems that support Motif, which happen to include many UNIX systems. But OS/2 and Windows don’t support Motif; instead they have their own window managers. Nevertheless, by incorporating a common Motif-like layer on these platforms as well as UNIX, IBM Smalltalk ensures that applications built on this
layer will be highly portable among the three platforms—UNIX, Windows, and OS/2. Moreover, because this Motif layer ultimately translates to the underlying platform's windowing system, the look and feel of user interfaces conform to the platform's native look and feel.

## 12.1 What you need to know about Motif

Conventional Motif is itself built atop another standard, X-Windows. The X-Windows interface consists of a collection of function calls called Xlib, or the X/Library. Motif is an example of an X toolkit; X toolkits are built on an interface called the Xt Intrinsics (X toolkit Intrinsics), which in turn is built from the Xlib. Thus, the conventional Motif layering looks like this:

<figure><img src="image_74.png" /></figure>

IBM Smalltalk presents a layer of Smalltalk classes and methods that look like Motif<fnref n="1" /> services, but are built atop the operating system's GUI services. In other words, the IBM Smalltalk Motif layer is built on whatever the underlying platform offers, be it raw OS/2 or Windows GUI services, or a real Motif toolkit and Motif window manager (mwm) like the picture above. The picture for IBM Smalltalk is:

<figure><img src="image_75.png" /></figure>

Two other abbreviations—Cw and Cg—occur commonly in IBM Smalltalk's UI classes. “Cw” stands for common widgets. Widget<fnref n="2" /> is the term that X programmers use for any UI component—be it a button, a scrollbar, a textual field, a label.... The counterparts in IBM Smalltalk of Motif's widgets are known as common widgets, and their class names are prefixed by “Cw.” Similarly, functions in the Xlib for graphics—drawing, bitmaps, fonts, color palettes—have been structured into Smalltalk classes that are prefixed by “Cg,” for common graphics.

The first window you build will contain a textual widget that displays 'Hello San Francisco'. Although this window, labeled myWindow below, is about as simple as they come, it relies on several Motif widgets, intertwined by instance variable relationships:

<footnote n="1">¹ By the way, Motif is sometimes abbreviated to *xm*, which stands for *X/Motif*.</footnote>

<footnote n="2">² Non-UNIX programmers often use the word *control* instead of *widget*. For our purposes UI widgets and UI controls are synonymous.</footnote>
<figure><img src="image_76.png" /></figure>

You can see where a textual widget would be, at the bottom of the sketch. Note that it is a child of a **CwForm**. Forms are container widgets; a form typically will contain several other widgets, although in your first application it will contain only one text widget, a **CwText**, for presenting the string '*Hello San Francisco*'. The highest level in the sketch is a **CwTopLevelShell**. As its name implies, it is the Motif widget that forms a "shell" over all the other widgets. A *main window* (*CwMainWindow*) is also a container; in addition to its forms it can contain a menu bar, should an application require one.

Notice also the *callback* objects at the lower left. Callbacks or, more precisely, callback handlers, are methods that are triggered by events like resizing or exposing a window.Widgets can respond to events like these by executing an appropriate callback handler. I will say more about callbacks later on.

The sketch above is schematic. The actual instance variable names are somewhat less readable. They have names like `cwChild`, `cwParent`, and `xmNChildren`.

Each of the Motif-like common widgets in the sketch above encapsulates a similar but more primitive object, which in turn encapsulates a really primitive operating system object known as a *window handle*:
<figure><img src="image_77.png" /></figure>

These primitive objects tie the common widgets to the real operating system. Fortunately, though, you can write all the code you need at the common widget level, and trust that the rest has been correctly encapsulated to do your bidding.

## 12.2 Widget resources

Widgets must be customized for each application. Customization covers everything from where the widget should be positioned to how it responds to events like button presses. To customize a widget, you send it appropriate customization messages. Customization is also known as setting the widget's resources. Here are some examples of setting resources for a widget w:

<table><tr><td>w topAttachment: XmATTACHFORM</td><td>Attach the top of w to the top of its form</td></tr><tr><td>w bottomAttachment: XmATTACHPOSITION; bottomPosition: 10 "percent"</td><td>Attach the bottom of w 1/10 of the way down from the top of its form</td></tr><tr><td>w topAttachment: XmATTACHWIDGET; topWidget: anotherWidget</td><td>Attach the top of w to the (bottom) of another widget referred to as anotherWidget</td></tr></table>
<table><tr><td>w editMode: XmMULTILINEEDIT</td><td>Assuming w is an instance of CwText, let it handle multiple lines of text, instead of just one line</td></tr><tr><td>w value: self myMethod</td><td>Assuming w is an instance of CwText, set the text it contains to a string that myMethod returns</td></tr><tr><td>w items: self yourMethod</td><td>Assuming w is an instance of CwList, set the items in the list to a collection of strings that yourMethod returns</td></tr><tr><td>w addEventHandler: ButtonPressMask<br/>receiver: self<br/>selector: #pushMe:clientData:callData:<br/>clientData: nil;</td><td>Assuming w is an instance of Cw FACILITY, let its response to a button press be defined by a method named pushMe:clientData:callData:</td></tr></table>

The peculiar-looking constants `XmATTACHFORM`, `ButtonPressMask`, and so on are defined in pool dictionaries, which I'll explain in the next section.

## 12.3 Excursion: pool dictionaries

Any software that talks to an external system must use the same low-level indicators (typically flags or masks that are bits or integers) that the external system uses. For example, on OS/2 the color dark blue is indicated by 9, and red by 2; any software running on OS/2 must use these same numbers for the same colors. We would like to think about the numbers as little as possible, of course, and instead refer to them by names like `ClrDarkblue` and `ClrRed`. Similarly, Motif resource values like `XmATTACHWIDGET` are easier to remember than arbitrary integers. (`XmATTACHWIDGET` happens to be 3 in Motif.)

Smalltalk pool dictionaries are handy objects for bundling constants like these. Pool dictionaries are dictionaries that have strings such as `'ClrDarkblue'` for keys and values such as `9`. (In IBM Smalltalk, pool dictionaries are instances of the special class `EsPoolDictionary`, which accepts only strings as keys.) For example, the global variable `PlatformConstants` refers to a pool dictionary that contains color constants as well as many other constants. And the global variable `CwConstants` refers to a pool dictionary that contains the resource values for Motif widgets.

So far in this discussion, we haven't used pool dictionaries in any unusual way. If you were to access one of its entries, you would have to write something like:

`widget topAttachment: (CwConstants at: 'XmATTACHWIDGET')`
just as you would refer to an entry in any other dictionary. The effect would be to pass 3 as an argument, but of course we don't want to write a 3 in our code.

The attraction of a pool dictionary appears when you specify one as part of the definition of a class:

```python
Object subclass: #MyClass
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: 'CwConstants'
```

Now if you want to access an entry in a method, you can simply write:

```python
widget topAttachment: XmATTACHWIDGET
```

No need to specify the dictionary or use the `at:` message! The Smalltalk compiler searches through the class's pool dictionaries for a key that matches the string `'Xm-ATTACHWIDGET'`. When it finds the key in `CwConstants` it compiles the association into the compiled method.

In short, pool dictionaries make code more succinct by saving you the trouble of typing the name of a dictionary every time you want to refer to an entry.

Here are some characteristics of pool dictionaries:

* The keys are strings.

* The values are often integers. (But not always. Try *inspecting* the pool dictionary `PlatformFunctions`, then double-clicking on one of its entries.)

* A global variable refers to it. (Otherwise there is no name by which to specify it when defining a class.)

* The dictionary should be fully populated beforehand. (If a key is absent, a method that uses it cannot compile.)

To solidify your understanding of pool dictionaries, try these simple exercises:

* What is the underlying value of `ButtonPressMask`? `ClrYellow`?

* Construct a pool dictionary as follows:

```python
Smalltalk declarePoolDictionary: #MyPool.
MyPool at: 'ABC' put: 55.
```

Now build a subclass of `Object` called `MyClass`, being careful to specify `MyPool` as a pool dictionary. Write this instance method:

```python
test
    " Test by displaying:
        MyClass new test
    "
    ^ABC
```
Predict the result and run the experiment to confirm your prediction. What happens if you write another test method that returns XYZ instead of ABC?

*Technical curiosity:* A pool dictionary can begin life as an ordinary dictionary, that is, as an instance of *Dictionary*. As soon as you use it as a pool dictionary though, IBM Smalltalk automatically converts it to an instance of *EsPoolDictionary*.

## 12.4 Exercise: a first window

The goal for your first window is something like:

<figure><img src="image_78.png" /></figure>

* Create a new application, or add to one of your old ones. Change the *prerequisite* applications to include *EtBaseTools* so that you can access class *EtWindow*. Add a subclass *HelloWindow* to *EtWindow*.

* Write an example class method for testing:

```java
example
    HelloWindow example

^HelloWindow new open
```

* Write an instance method that answers any string you like:

```java
myHello
    ^ Hello San Francisco'
```

* Remember that abstract classes come with expectations that their subclasses fulfill certain obligations. For the abstract class *EtWindow*, its subclasses must implement the method *createWorkRegion*. Write this method in your *HelloWindow* class.

```java
createWorkRegion
    | textWidget|
    textWidget := workRegion
    createText: 'My text widget'
```
```python
argBlock:
    [:w | w
        editMode: XmMULTILINEEDIT;
        value: self myHello;
        leftAttachment: XmATTACHFORM;
        rightAttachment: XmATTACHFORM;
        topAttachment: XmATTACHFORM;
        bottomAttachment: XmATTACHFORM].

textWidget manageChild
```

This method looks more formidable than it is. The important messages are the resource-setting messages inside the block. You should recognize their purposes from the last section.

* Finally, test your `HelloWindow` class by executing your example method.

## 12.5 Exercise: a window for the account balance

You are about to add a simple user interface to the bank account you developed in Chapter 8. You want to end up with a window representing the account, with separate widgets to contain the transaction log and the current balance. We'll proceed in three steps: first a window that displays only the balance, then one that displays only the transaction log, and finally one window that displays both the balance and the log, using two widgets.

* Begin by choosing a suitable application, like the one in which you wrote your earlier account exercise, and change the prerequisites so that they include `EtBaseTools`. Add a subclass, `BalanceWindow`, to `EtWindow`. The fundamental difference between this exercise and the preceding "Hello" exercise is the need for the window to know about an account object. Create an instance variable named `account` in `BalanceWindow` for this purpose.

* Prepare a test case by writing this class method in `BalanceWindow`:
  ```python
  example
  ```
  BalanceWindow example
  ```
  ^BalanceWindow new openOn: Account example.

This test case reuses `Account`'s class method `example`, which you developed on page 91.
* Note that you will need an `openOn:` instance method that takes an account as an argument. Write this method. It should do just two things: set the instance variable and open the window (by saying `self open`).

* Instead of `myHello`, write an appropriate method to return the account's balance. Don't forget that the returned object should be a string. In other words, don't forget to convert the integer balance to a string.

* Finally, write a `createWorkRegion` method and test by executing your example method.

## 12.6 Exercise: a window for the transaction log

In this exercise, you will need to transform one collection into a different, brand-new one. One way would be to write a loop. However, object-oriented developers rarely write loops to process collections. Mature class libraries have powerful methods (or even objects, called *iterators*) that process a collection's contents. In Smalltalk, the method `Collection>>collect:` processes each element in a collection and puts the resulting objects into a new collection.

* Display each of these lines:
  (OrderedCollection with: 3 with: 2 with: 1) collect: [:x | x squared].
  (SortedCollection with: 3 with: 2 with: 1) collect: [:x | x squared].

* Mimic the steps in the previous exercise: start with a class called `LogWindow`, write an example class method, and an `openOn:` instance method.

* Your `createWorkRegion` method should be similar to the one for displaying the account's balance. That one built a text widget, however, and this one should build a list widget. Thus, part of it should look like:

```ruby
listWidget := workRegion
  createList: 'My log widget'
  argBlock:
    [:w |
     w
        items: self myLog;
        leftAttachment: XmATTACHFORM;
        ...
      ].
```

Write the `createWorkRegion` method.
* To complete the code, you must write the `myLog` instance method specified in your `createWorkRegion` method. `myLog` should use `collect:` to transform the transaction log into an `OrderedCollection` of strings.

* Execute your example method to test that your window displays the transactions in chronological order.

## 12.7 Exercise: a window containing both widgets

* Build a class called `AccountWindow`. This window should combine ideas from the preceding exercises so that it displays both the balance and the transactions.

## 12.8 Assessment: building windows

You've now seen what it takes to build simple windows using Motif. In general, one subclasses from a suitable abstract window class. `EtWindow` is one example, because it is the abstract window class for all the everyday browsers and tools you use in IBM Smalltalk. Theoretically `EtWindow` is not the best choice of superclass for a product that will be delivered to a customer. That's because it was designed as the basis for the development-time windows, and a product's code shouldn't depend on development-time code. In fact, `Et` stands for "Envy Tools," where Envy is a suite of team programming facilities that is also available in other Smalltalk environments.

Another starting point could have been the abstract class `WidgetWindow`, best found by loading the application `CwExamples` and its prerequisites. To use `WidgetWindow` as a superclass, you would write a `createWindow` method instead of the `createWorkRegion` you wrote in the exercise.

Another prospective starting point is the class named `WbApplication` (part of the public-domain application `WbApplicationFramework`), which is the abstract window class of the third-party product `WindowBuilder Pro`; you override the method `addWidgets` instead of `createWorkRegion`. `WbApplication` can thus serve as the superclass of handcrafted windows as well as of windows generated by the `WindowBuilder Pro` GUI builder.

Or, you could start by writing your own simple abstract class, including code to create the top-level shell, a main window, and any other standard fixtures you want your windows to enjoy.

These are all legitimate approaches to handcrafting windows. They are valid even for building elaborate windows consisting of numerous, carefully positioned widgets. But as I said earlier, you are most likely to use a GUI building tool to lay out such
windows. For IBM Smalltalk, that is likely to be VisualAge or WindowBuilder Pro. VisualAge offers the attraction of visual programming, which means that you can con- nect user interface and model components together to produce working logic, without even writing Smalltalk code. WindowBuilder Pro uses fewer layers of objects and so offers efficiency plus the virtue of making Motif widgets accessible should you need to work with them.

Good sources of additional details about Motif programming in IBM Smalltalk are the product manuals [IBM 1995] and [Objectshare 1995].

12.9 Callbacks and events

Your windows so far don’t respond to any inputs and therefore aren’t too practical. Practical windows respond to mouse actions and other events (or X events) from the operating system. These include typing on the keyboard, moving the mouse, resizing or exposing a window, giving a window the focus, and so on. You can think of events as stimuli that the operating system detects from physical devices and passes on to your widgets. (In X-Windows, the component of the system responsible for this ser- vice is known as the X server.)

A widget won’t respond to an event unless it has been sensitized to the event. To sensitize a widget to an event, you must establish an event handler. You will write event handlers in the upcoming exercise.

Sometimes it may be convenient to think of higher-level, or "artificial" events. For example, it would be reasonable to want to sensitize a button widget to a "click," which consists of two events, namely a button press followed by a button release, both of which must occur over the widget. A click lifts the programmer’s level of abstraction above the raw hardware concerns of a mouse press and release occurring in just the right sequence and place. In Motif and other windowing systems, these artificial events are known as callbacks. (The callback for clicking on a CwPushButton widget is known as an activateCallback or XmNactivateCallback.)

The programmer writes event handlers for events, and callback handlers for call- backs. Both event handlers and callback handlers are special methods that execute whenever the expected stimuli occur. The reason for the name "callback" is that when the stimulus occurs, the operating system "calls your widget back" and gives it the opportunity to execute its handler. A callback is similar to arranging for someone to call you back later on the telephone: you expect the callback to occur and you will be ready for it, but you’re not sure when it will happen.

Events and callbacks are similar. The programmer sensitizes the widget to either one by establishing handlers, and the operating system calls back when the stimulus
occurs. The distinction between them—events being low level and callbacks being higher level—is a Motif convention. In other object-oriented environments, the word "callback" applies to all stimuli, whether they are low or high level. In fact, Smalltalk programmers frequently use the term "callback" for any call of a Smalltalk method that originates from outside of Smalltalk.

How does a callback (or event) differ from a conventional call? The distinction is partly one of degree. For one thing, most callbacks represent primitive stimuli and therefore carry less information (fewer and simpler arguments) than conventional calls can. But the principal conceptual distinction has to do with concurrency. After a view establishes a callback handler it continues to execute other code; it does not block and await the callback. Instead, the callback occurs asynchronously, at some unforeseeable future time, when the view could be doing anything at all. From the view's perspective, the callback has an event-driven flavor rather than a procedural one.

## 12.10 Preparation

A CgDrawable (and its subclass CgWindow) can display graphics that are "drawn" on it by a *graphics context*, an instance of CgGC. You can think of a graphics context as a drawing tool like a pen or brush. Here are examples of CgDrawable drawing methods:

```
CgDrawable>>drawPoint:x:y:
CgDrawable>>drawLine:x1:y1:x2:y2:
CgDrawable>>drawRectangle:x:y:width:height:
```

* What kind of object do you expect the first keyword argument in each of these methods to be? If you are uncertain, verify your answer by browsing class CgDrawable.

## 12.11 Exercise: mouse event handling

The result of this exercise will be a window in which you can "doodle" with the mouse.

* Load the CgExamples application into your image, if it is not already present. (To install it in the standard environment, start from your System Transcript and pick menu options Smalltalk tools > Load Features... then select Smalltalk Programming Examples. To load it in the Professional environment, start from an Application Manager window and pick menu options Applications > Available > Application.) You can now access the abstract class CgSingleDrawingAreaApplication. This abstract class has both a drawing widget (CgWindow) and a graphics context built into it; therefore its concrete subclasses can "draw."
* Which instance variable in the abstract class refers to the graphics context? Which refers to the drawing widget?

* From your Application Manager, create a new application in which to write your code. Change the application's prerequisites to include `CgExamples`.

* Add a subclass `DoodleWindow` to `CgSingleDrawingAreaApplication`. Add two instance variables, `oldX` and `oldY`. You will use these instance variables to retain the previous position of the mouse as the mouse moves.

* Write a class method to test your application:
  example

DoodleWindow example

^DoodleWindow new open

* Look at the inherited `buttonMotion:` and `buttonPress:` event handlers. Note that the argument they expect is an event, actually an instance of `CwMotionEvent` or `CwButtonEvent`. What methods can you use to get the x and y coordinates of the point at which the event occurred?

* Finally, override the event handlers `buttonMotion:` and `buttonPress:` and test your window.

## 12.12 Challenging exercise: dynamic updates

* The account window displays both a balance and a list of transactions, but it is still relatively inert because it provides no way to add new transactions. Extend the window so that the user can create and handle new transactions. You can consider either of two UI designs:

* Add a button to the window. When the user clicks the button, another window or dialogue box should open and let the user fill in a date and amount for the new transaction. When the user completes this dialogue, the original window should refresh with an updated balance and transaction log.

* Add a date field, an amount field, and a button to the window. When the user completes the date and amount, then clicks the button, the balance and transaction log should refresh.
This is not an easy exercise. Without a GUI builder, it requires a healthy dose of exploration and experimentation. It is a good idea to have an experienced Smalltalk programmer around in case you get stuck.

## 12.13 Summary

Object-oriented user interface programming has an event-driven flavor. The programmer establishes handlers for system events or callbacks, and the specified handlers execute when the events occur. Typically, these events occur at a time and place determined by overt user actions, like clicking a mouse at a point on the screen. Thus the event-driven programming model tends to liberate users, letting them perform whatever actions they want whenever they want to. User interfaces that fulfill this promise, so that the user is rarely forced to deal with a fixed situation before proceeding, are called *non-modal* user interfaces. (Not every user interface programmed with objects is non-modal. For example, a user interface in which button clicks or menu picks present dialogue boxes that the user *must* complete before proceeding may look as if it has been programmed with objects, but it won't feel that way.)

Now consider a procedural or function-oriented programming model, in which the application decomposes into a tree of sub-functions. In the classic user interface for this model, interaction occurs mostly through a formidable hierarchy of menus. This kind of user interface puts the application squarely in control of the user, who feels psychologically straitjacketed by it. Such user interfaces, in which users must act in rigidly prescribed ways to proceed or extricate themselves from a situation, are an extreme form of modal user interface.

Events and callbacks originated in Smalltalk-80, where widgets were known as *views*. By supporting different handlers for an event, a view could be customized for different problems. They were therefore called *pluggable views*: if you needed a view with specialized behavior, it was enough to plug one of these views into the overall application window and establish specialized handlers for it. Without pluggable views, you would have had to add a whole new view class to get the behavior you wanted. In other words, you could either "buy" a pluggable view and customize it, or "inherit" from another view and customize that. Nowadays, the variety of widgets and their pluggability is rich enough that you don't need to create new widget classes for most ordinary applications.

So far, I have discussed only events or callbacks that pass through the operating system—that is, stimuli that arise from outside Smalltalk. A similar logical flow can occur strictly within the confines of Smalltalk. For instance, an MVC or MV broadcast is like a callback. The view establishes a handler, namely its *update* method, written
according to the problem or model at hand, and this handler executes whenever the model calls the view back with a broadcast. Some broadcast mechanisms allow you to call back clusters of messages with arguments, instead of just update. The VisualAge and VisualSmalltalk products support such mechanisms. (Cf. the table on page 125.) Programmers and frameworks sometimes also use these mechanisms for model-to-model broadcasting. (But approach such usage warily, because excessive broadcasting can measurably degrade performance.)

Finally, today's GUI builders relieve you of having to build the UI, but you still have to design it. Good UI design is much more than assembling widgets into a window, and is the subject of the next chapter. Users of powerful GUI builders sometimes backslide from good model-view separations. Carried away by power and speed, they connect user interface widgets directly to low-level components like database elements, without thinking about appropriate model objects.

We can suffer the same lapse even without a GUI builder. In our rush to build `HelloWindow`, we didn't stop to think about a model class. We adopted a style of user interface programming in which we subclassed from an abstract superclass that provided standard view capabilities. We thought of the application as a kind of window. No model class encapsulated the application's logic. Such a fall from grace is pardonable for a simple example like `HelloWindow`, which has no interesting application logic. It is a benign step in the wrong direction; it is perilous only if we begin to build applications where a monolithic window class is suffused with application logic. We avoided this misstep with the account windows by using a separate model class (Account) that encapsulated the application's behavior.
CHAPTER 13

Designing the UI: a brief tour

The preceding two chapters covered the principle of separating models from views and the actual programming that goes into constructing windows. You should now have a solid grasp on the mechanics of a user interface. We next approach the hardest, most ineffable aspect of user interfaces—designing them.

13.1 User interfaces

The user interface (UI) is the sole point of contact between a user and the computer. As far as the user knows, the user interface is the computer. But even though the user interacts with nothing else, a lot happens in her mind. The appearance of the UI evokes images, just as a novel evokes mental images in the reader's mind. And the more the user interacts with the UI, the further she refines these images, imbuing them with their own imagined behavior, as a child imbues a talking doll with imagined behavior. Unfortunately, the UI's evocations are rarely as effective as the novel's or the doll's. The quality of that evocation is precisely what distinguishes bad user interfaces from good ones, hence bad computer software from good.

The premise in this chapter is that it is worth investing in the design of your application's user interface. An application's acceptability in the marketplace can pivot on the difference between a good user interface and a mediocre one. Although this chapter is not a complete treatise on designing user interfaces, I present some simple, generally overlooked principles that are at the heart of designing respectable UIs. Along the way, we will again meet the principles of object-orientation.
## 13.2 Elementary examples

Consider two user interfaces for a chess program, one in which the user interacts by typing commands of the form "Nd5," the other in which she uses a mouse to drag an icon depicting a pawn to a square on an image of a board. The game is the same, but the user interfaces create very different impressions on the user.

Or imagine an interactive video game, rendered not with images of protagonists in fast-breaking life-and-death situations and real-time feedback between a control stick and the images on the screen, but sentences on the screen describing the action and a keyboard for typing moves. Again, same game, different user interfaces. One works; the other elicits, at best, indifference. The quality of the user interface foretells a product's acceptability.

Designing a user interface for a game is not a hard problem. (Implementing it may be another matter.) The reason goes to the heart of this chapter: a computer user interface for a game should be a metaphor for the real game. No other user interface makes sense. If the game involves chess pieces, the user interface should represent chess pieces; if the game involves militant people or rocket ships, the user interface should represent militant people or rocket ships. The elements of these games are tangible, recognizable objects, and end users won't settle for less than faithful representations of these objects on their computers.

Contrast this situation with other applications: it is much harder to design a good user interface for a typical software application than it is for a game. A word processor deals with intangible, uncommon entities—styles, paragraphs, fonts, tables, frames, layouts, footnotes. It is altogether more complex than a game; devoid of blatant metaphors. What's more, a game has well-defined rules and actions, so the actions that its user interface should accommodate must be equally well defined. Not so for a word processor. Contemporary WYSIWYG<fnref n="1" /> word processors confront users with a daunting array of icons and menus, offering much richer and less constrained capabilities than any sensible game does. No wonder it takes so long to become proficient at powerful software applications; users just cannot get much metaphorical guidance from their user interfaces.

The essence of the difficulty is the absence of a simple, underlying model. When such a model exists, as for a game, the UI can be designed to portray the model. Without a simple model, user interface designers facing an inherently complex problem like word processing have little to guide them.

<footnote n="1">¹ "What You See Is What You Get"</footnote>
### 13.3 Coherent conceptual models

The models discussed in the last paragraph are *conceptual models*. By a conceptual model I mean words, metaphors, pictures, rules, or anything that you use to explain how you think something fits together. A superior conceptual model sharpens your understanding of the subject. Here are some examples from my own experience:

* Many people automatically call a tree with needles a pine. Some do so uneasily, because they know that other trees such as firs and spruces have needles too. But they still call them all pines. Their conceptual model for a pine is “a tree with needles.” A better (and correct) conceptual model for a pine is “a tree with needles bundled in a sheath at their base”:

<figure><img src="image_79.png" /></figure>

With this conceptual model, it is hard to mistake a spruce for a pine.

* My conceptual model for a printer driver used to be “a piece of software that comes with a printer and allows the computer to send output to the printer.” But every FAX program I’ve seen comes with a printer driver too. Why do I need a FAX printer driver? (I didn’t know.) If I needed to print a FAX, wouldn’t I simply have used my printer’s driver? (Yes.) I eventually realized that a FAX printer driver was the means by which I could send FAXes through the modem in my computer, *instead* of printing them. To make sense of this revelation, I had to adjust my conceptual model of a printer driver to “a piece of software that handles an application’s print commands.” This improved conceptual model neatly implies that anything that is printable is also FAX-able.

<figure><img src="image_80.png" /></figure>

* A teacher of new computer users told me that when she asked them to “move the mouse to the top of the display,” some of them lifted their mice into the air and
placed them on top of their monitors. They were unfamiliar with the direct manip-
ulation conceptual model, in which the mouse *is*, in effect, something on the screen.

<figure><img src="image_81.png" /></figure>

<figure><img src="image_82.png" /></figure>

Users are not to blame; if computing is to be attractive and helpful, the computer industry had better clearly convey conceptual models to its users.

If conceptual models are the means by which we understand a subject, it follows that they had better be *coherent*—their parts must fit together in a natural, easily understood manner. Only then will users find them memorable and meaningful. On the right is an attempt to portray a conceptual model for a face. A face designer would be satisfied that it contains all the right elements—eyes, nose, mouth, and so on.

Now consider an upside-down version of the same face. Study it carefully, without turning the page upside down. This lets you analyze it without being influenced by your usual intuitions about faces.

Aside from the irrelevant fact that it is upside down, is this model equally coherent? Can you discern any incoherent elements? It should take a few moments before you notice them: the mouth and eyes are oriented right side up. Thus, a face designer would eventually concede that the elements are not assembled coherently, even though all the right elements are present.

Users, on the other hand, do not have the designers' patience for analyzing a model's coherence. To appreciate

<figure><img src="image_83.png" /></figure>

<figure><img src="image_84.png" /></figure>
their perspective, turn the page upside down now. This conceptual model of a face is immediately and unmistakably incoherent. Users arrive at the same conclusion as the designer eventually ought to, but more quickly, and by a different cognitive process.<fnref n="2" />

The analogy here for user interface design is that to achieve a successful user interface the designer must describe not only a conceptual model, but one that is coherent. If the designer has no conceptual model at all, the user will never make sense of the user interface. A little better than having none at all is having one that is incoherent. This is the most common situation, where the designer settles for a conceptual model that nevertheless baffles the user. Best and rarest, and the only hope for comfortable, intuitive user interfaces, are coherent conceptual models.

In practice, conceptual models function at more than one level. In the word-processing example, one elemental conceptual model is that a word processor behaves something like a typewriter. Another is that the result can be stored indefinitely and recalled and changed at will. Another is spell-checking. Another is paragraph styles. The overall conceptual model of a word processor consists of how these hundreds of lesser models fit together. (Note that assembling them coherently is a herculean task.)

At another level, many word processors employ scrollbars, a toolbar with iconic buttons, menus, and dialogue boxes. For each of these widgets, users have developed expectations for their behavior: "dragging a scrollbar moves a window over the document," "clicking a menu title drops down a list of menu selections," and so on. These expectations are conceptual models for each kind of widget. Failure to recognize any one of these conceptual models at either level will be a major obstacle in using the word processor.

Because conceptual models are the means by which we understand the world, it behooves us to find effective ways to describe them. There is no one answer, but the next section brings one of humankind's most powerful cognitive tools to bear on the problem.

## 13.4 Metaphor

*Metaphor* is the use of one idea in place of another to suggest some likeness. If I tell you that my office is a pigsty, I am using a metaphor. I don't mean that pigs actually

<footnote n="2">² The brain has wiring for face (or landscape) recognition. Turning the image upside down disables this wiring. That's why we are unaware of how seriously amiss things are in the upside-down image. Some people lose this wiring completely, even for right-side-up images. They develop *visual agnosia*, a right-brain disorder in which they can no longer recognize faces, or assemble visual wholes from parts. See [Sacks 1985].</footnote>
inhabit the place; rather I mean to suggest the disarray of a pigsty. A good metaphor is a powerful cognitive tool because it is a form of reuse. The mind applies its knowledge of something it already knows to something it doesn't.

Most people claim that it is difficult for them to think metaphorically. But in fact they use metaphors all the time without realizing it. "That sofa weighs a ton." "He reminds me of a politician." "She is dancing on air." When taken far enough, practically everything we say has a metaphorical root. Consider:

> [The dog] flashed and darted hither and thither as if fairly demented, screaming and shouting, swirling round and round in giddy loops and circles like a leaf in a whirlwind. [Muir ca. 1880]

How many metaphors do you count? Two are conspicuous: likening the dog to a lunatic and also to a leaf caught in a whirlwind.

But probe a little deeper. Where do words come from? Someone had to invent them. The word *flash* came about by onomatopoeia—it sounds like the idea it represents. Just hearing the word evokes the image of something that swiftly comes and goes. Someone made it up for this reason. *Darts* were originally pointed weapons thrown by hand (surviving today in the form of a game); here they are a metaphor for the dog's abrupt movements. Whoever first used the word *circle* was connecting it to the Greek word for ring, *kirkos*. For that individual, a ring was a metaphor for a circle, and we now accept the invention without reflecting on its metaphorical origin. The word *shout* goes back to an Old Norse word for a taunt, *skúta*. *Demented* derives from the Latin *de*, meaning out of, and *mens*, meaning mind. And so on.

In short, every word comes about because somebody connected it to an idea, and so a metaphor lies somewhere behind every word we use. Instead of insisting that it is hard for us to think metaphorically, we should concede that it is hard for us to think in any other way. Everything's meaning is based on the meaning of something else. Metaphorical thinking is part of our cognitive core, whether we consciously acknowledge it or not.

What metaphors could describe the conceptual models for the word-processing example? It is like a *typewriter*, but it can do more. It can *remember* documents. Text can be rearranged like *building blocks*. It works with a *dictionary* to check spelling. To someone who has never experienced word processing, or even a computer, metaphors like these may convey conceptual models more concisely and vividly than a literal description of the software's capabilities.

Just as conceptual models apply at different levels, so do metaphors. Here are some application-level metaphors that have profoundly influenced the computer industry:
<table><thead><tr><td>Application</td><td>Metaphor</td></tr></thead><tbody><tr><td>VisiCalc (first spreadsheet, precursor of Lotus 1-2-3)</td><td>Bookkeeper's ledger sheet</td></tr><tr><td>Pong (first video game)</td><td>Ping pong</td></tr><tr><td>Xerox Star (first office GUI, precursor of Apple Lisa and Macintosh)</td><td>Desktop</td></tr><tr><td>SQL</td><td>Predicate logic</td></tr><tr><td>Word processor</td><td>Typewriter + dictionary + style guide + ...</td></tr></tbody></table>

And here are some metaphors at the level of user interface components:

<table><thead><tr><td>User Interface Function or Widget</td><td>Metaphor</td></tr></thead><tbody><tr><td>Menu</td><td>Restaurant menu</td></tr><tr><td>Scrollbar</td><td>Sliding window</td></tr><tr><td>Dragging hand</td><td>Sliding paper</td></tr><tr><td>Drag and drop</td><td>Moving</td></tr><tr><td>Folder icon</td><td>Container</td></tr><tr><td>Radio button group</td><td>Radio presets</td></tr></tbody></table>

In Chapter 1, I emphasized the value of metaphors in thinking about programming objects. In this chapter we've extended their reach from programming objects to conceptual models. As before, I'm not interested in the fine distinctions among metaphor, simile, analogy, and imagery. Their important common characteristic is that they use one idea to suggest something about another idea.

## 13.5 Magic

The remaining consideration for designing good user interfaces is *magic*. If a computer application does neither more nor less than the metaphor it is based on, there's no point to it. A word processor that exactly duplicates a typewriter's function is no better than a typewriter. *Magic* is the term that user interface designers use to describe the ways in which a computer application goes beyond what the original metaphor suggests.

A spreadsheet program goes beyond a bookkeeper's ledger sheet in two stunning ways. First, it permits the user to enter formulas where the bookkeeper would have had to calculate a cell's value by hand, and second, it can automatically recalculate
these formulas when the cells on which the formulas depend change. We take for granted these capabilities that VisiCalc first introduced in 1978. But VisiCalc, graced with this magic, became the first major commercial personal computer application and was an early driving force in the personal computer revolution.

Many people form minor addictions to the simple solitaire card game in Microsoft Windows. Its conceptual model (and metaphor) is the real card game, Klondike solitaire. The software provides exactly the same functions as the player with a card deck does. Its magic consists of the ways in which it is faster and less troublesome to play than the real version. Starting a new game requires only a menu pick, not a physical and time-consuming shuffle and deal; this magic overcomes the chief obstacle to playing "just one more game." Moving a run of cards by dragging and dropping is lazier and tidier than moving real cards. Turning over cards by pointing and clicking takes less energy than grasping and flipping a real card. Overall, the software version affords the same intellectual challenge as the real version, but requires markedly less physical effort to play, on account of its magic.<fnref n="3" />

Magic fosters good software, but magic gone awry is treacherous. Getting the right balance of magic is part of the challenge in user interface design. Consider the Macintosh trash can. To delete an item, the user drags and drops it into the trash can. The metaphor is so faithful to a real trash can that you can recover items by opening up the can and examining its contents. To permanently delete its contents, you must explicitly "empty the trash."

But the trash can has another magical property: if you want to eject a diskette from the diskette drive, you drag and drop the diskette icon into the trash, too. Every new Macintosh user I've observed, including me, has been puzzled by this behavior, and at least momentarily concerned that they might be erasing all the files from their diskette. They adjust soon enough, but not before the initial scare.

Another example: The OS/2 shredder is based on the metaphor of a paper shredder. This metaphor works nicely for documents: drag a document's icon and drop it on the shredder and the shredder disposes of the document. Sometimes, though, icons represent programs instead of documents. And often, two icons representing the same program are tucked away in different places on a desktop. As a new user, I worried whenever I wanted to delete an extra icon. In my conceptual model, the icon *is* its underlying object (the program). Hence, if I shred the icon, the program must go with it, which is different from my intent.

<footnote n="3">³ Some critics believe this convenience is a bad thing. They argue that software games are detrimental because they distance their users from tangible reality. Essentially the same objections apply to television, breadmaking machines, digital images of art, even books.</footnote>
Fortunately in this situation, the shredder deletes only the icon and not the underlying program. This behavior isn't consistent with my innocent conceptual model, but at least it provides a way to do what I want to do. But the story doesn't end there. After I adjusted to this behavior, I stumbled on situations where shredding the icon also deletes the program! On these occasions, the innocent conceptual model is correct: the icon identifies with the underlying program file. (Icons found by starting with the "drives" icon behave in this way.) Unhappily, this kind of icon and the kind of icon that doesn't identify with the underlying program are visually indistinguishable. Same icons, different behaviors. The magic of shredding was designed to present an irreconcilable obstacle to consistent use of the user interface.<fnref n="4" /> (By the way, Windows and Windows95 suffer from the same ambiguity. In my experience, only the Macintosh is unambiguous about icon identity.)

A final illustration: in everyday life we often wish we could undo something that turned out badly. Examples range from staining the side of the house the wrong color, to disassembling a camera lens, to sewing an extra flap of fabric into a seam, to saying the wrong thing to someone. This wish occurs as often when working with computers as it does in real life. But in computer applications, it is theoretically possible to fulfill the wish. Some applications—the Microsoft Word and DeScribe word processors, the WindowBuilder Pro and VisualAge GUI builders come to mind—let their users undo an unlimited number of past actions. Users develop complete confidence that they can retrace their steps, and therefore are not reluctant to try bold new directions. Such undo magic is as good as it can get.

Unfortunately, most undo facilities are more limited. Some let you undo perhaps four actions, or warn you that specified actions are not undoable. This undo magic has gone awry. Users are burdened with remembering an arbitrary detail, like whether the state to which they wish to return is within the four-action limit. They stop using undo because they regard it as untrustworthy. The effect can be debilitating: they hesitate to risk actions whose results they are not sure of. One sees this hesitation in the use of photo-editing software, where they are inhibited from trying special effects because of the fear that they will not easily be able to return to an acceptable image.

Limited undo functions remind me of a timeless piece of wisdom, known as the "zero, one, infinity" rule: if you are going to design undo, make it support zero, one,

<footnote n="4">⁴ Computer scientists call these kinds of problems *aliasing problems*. This is an example of aliasing on the user interface. But aliasing problems pervade software, and object-oriented programming is no exception. In C++, every pointer is an opportunity for an aliasing bug. Smalltalk is a little better, because it has no explicit pointers. But implicit pointers are everywhere, so you can still encounter aliasing surprises. Refer to the aliasing exercise on page 59.</footnote>
or infinitely many undos. These are the only numbers that people can remember. We will revisit undo in Chapter 15, where we will discover an object-oriented design for infinite undo.

Magic is hard to get right. All of these examples—the Macintosh trash can, the OS/2 shredder, and undo facilities—are based on reasonable metaphors, but present disruptive magic. The resulting conceptual models aren't coherent.

Let's summarize the characteristics of good user interfaces: they are based on coherent conceptual models that are understood through carefully chosen metaphors. And they improve on these metaphors by just the right kind of magic—magic that adds power to users without disrupting their understanding of the user interface.

## 13.6 Exercise: design a user interface

Design the user interface for an application for managing addresses and phone numbers of friends, family, and associates. This is the “contact-management” component of products called *PIMs*, or *Personal Information Managers*. Be as imaginative and unconstrained as you like, but consider all these:

* Brainstorm until you have at least two metaphors for the user interface. (“It’s like a ______.”)

* Develop some high-level use cases. Brief descriptions of some of the user’s tasks will suffice.

* Choose one of your metaphors and outline your ideas for a user interface based on it. Use your use cases to evaluate (a) ease of learning, (b) ease of use, and (c) magic.

* As a responsible user interface designer, try to articulate one or more underlying conceptual models to a prospective end user. A good test for coherence of your conceptual model(s) is to limit how much you say. (Twenty seconds? Three sentences? One picture?) Imagine just one brief opportunity to convey the spirit of the application. The conceptual model(s) can be the same as your user interface metaphor, but it need not be.

This exercise produces the most interesting results if you can do it in a group of up to four people.
13.7 Discussion of your results

People who do this exercise invent all kinds of ingenious interaction techniques. Most are variations on the fine details in their chosen user interface metaphor. As for the metaphors themselves, the list of candidates seems short—three that I can distinguish. And no matter what the metaphor, the same conceptual model always emerges. Let's begin with the metaphors.

The two most popular user interface metaphors for contact management are the address book and the Rolodex. A real address book has some obvious limitations: you can't add pages if you need more space, and you can't order the entries. For instance, all names beginning with "S" are together, but not in any logical order. These limitations present obvious opportunities for magic—unlimited names and automatic alphabetic sorting. The result is a more gratifying address book than a real one. Notice that although unlimited pages and sorting are magical extensions for the address-book metaphor, they are already part of the Rolodex metaphor.

One interesting feature of real address books is the index tab. Imagine the use case of searching for a name, say, "Segovia." I pick the tab for the letter "S" first, then scan that page for "Segovia." Not bad. Those tabs on manual address books and Rolodexes were an inspired way to cope with large numbers of names. Far better than, say, a telephone book. But that was before computers. A computerized contact manager that makes me select an index tab to get to the vicinity of the name I want feels, well, inefficient. Computerized Rolodexes and address books both give users this feeling.

To overcome this problem, contact managers often provide a fast-path facility in which the user can type letters like "S-E-G" and immediately reach the first name that begins with "Seg." This technique is an appealing form of magic, but it doesn't quite fit with address books and Rolodexes. The user looking at an address book sees an alphabetic tab for the letter "S" that entices him to pick that tab to find "Segovia." The user may not guess that typing two or three characters will lead progressively to a matching entry. The technique is ingenious, but it differs sufficiently from the base metaphor that it runs the risk of appearing to be inconsistent.

Perhaps a computerized contact manager should do away with index tabs. Does such a design depart too radically from the world of real contact managers? Or is there a real-world contact manager that has no index tabs, on which we could model the computerized version?

Absolutely. The simplest real-world metaphor is one that people carry on a sheet or two of paper—a *list* of names and contact information. If a list of names on a sheet of paper is too dreadfully mundane a metaphor, you may consider a fancier version of the metaphor—your local telephone book. Either way, the designer can spruce up the user interface with a little magic: the user can scroll a window over the list (continuously,
and without artificial markers like the twenty-six letters of the alphabet); the user can search by typing "S-E-G" and the window will scroll farther as the user enters each letter; and selecting one name from the list can open a view of that individual's detailed contact information:

<figure><img src="image_85.png" /></figure>

This user interface is unencumbered by superfluous index tabs that set expectations more appropriate for physical contact managers than computerized ones.

We have concentrated so far on the use case of searching for a name. Other essential use cases are adding a new entry, deleting an obsolete one, or altering an existing one. You may also have considered use cases like dialing a phone number, sending e-mail, or printing an envelope, or variations of the essential use cases such as copying or sharing contact information from another contact. Sooner or later, in a real design effort, you would have to walk through detailed versions of each of these use cases. You would find the challenge to be in balancing faithfulness to the metaphor you've chosen with the magic you need to make the computerized version more usable than its real counterpart.

Finally, can you as a UI designer articulate a coherent conceptual model to the prospective end user? This is a serious challenge. For example, the designer who wants to say that the conceptual model is a Rolodex or address book, and then adds multiletter, progressive searching, will have a tough time arguing for coherence. First, you must succeed in articulating a coherent conceptual model to yourself. Thinking back to model-view architectures (Chapter 11), a good place to begin is to imagine the model objects you would need.

Regardless of the UI metaphor you started with, it doesn't take long to concede that a Person or Contact class, and a suitable container to hold them, like a Sorted-Collection, are unavoidable. Rolodex and address-book UI designers also need a
**Rolodex** or **AddressBook** class, respectively. List or telephone-book UI designers quickly recognize that they will need a class that supplies the magical behavior for their views too. They might name this class **PaperList** or **TelephoneBook**. The striking result of all three approaches is that, regardless of the user interface metaphor, the model objects end up configured something like this:

<figure><img src="image_86.png" /></figure>

These model objects can service any of the three user interfaces—the three views. Any behavior beyond what a container like a **SortedCollection** can manage resides mainly in the **Rolodex/AddressBook/PaperList** class.

You have actually used this configuration of objects before, in the checking account exercise in Chapter 7. Compare the sketch here with the CRC cards illustrated on page 86. The resemblance is not coincidental; this configuration of objects solves many design problems. Recurring configurations like this are known as design patterns (Chapter 18).

Notice that this common conceptual model resembles address books and Rolodexes least. In fact, it's not very different from the paper-list metaphor. For one thing, the index tabs that are an artifact of the other metaphors and so strongly predispose users to search for and add names by tabbing to a specific letter, are absent. Because tabs don't intrude on a paper list, both it and the conceptual model are free of the biases with which magic multiletter progressive searching might clash. That the paper-list metaphor aligns so well with the conceptual model (they are *isomorphic*—see the next section) suggests that computerized lists may be desirable user interfaces for contact-management applications. The irony is that so many contact-manager user interfaces today look like address books and Rolodexes, in spite of the dissonance with the underlying conceptual model.
The sketch above is a satisfactory way for the user interface designer who knows about object-oriented programming to picture how the application fits together. It constitutes a coherent conceptual model. The same sketch can conjure up a coherent conceptual model for the user: the user can imagine a sophisticated main object that has a container of contacts. A conceptual model shared between user and designer—even one as simple as this sketch—is the essence of successful user interface design.

## 13.8 Isomorphism

The sharing of a conceptual model by user and designer is an example of isomorphism (from the Greek, *iso* = same, *morphism* = form). In a successful user interface, the user's and designer's conceptual models have the same form. If a user can learn the user interface quickly, this shared conceptual model is probably coherent too. This isomorphism is illustrated in the following picture, with the designer's thoughts at the left and the user's on the right:

<figure><img src="image_87.png" /></figure>

Once the product is out the door, the only way for the designer to convey the conceptual model to a user is through the user interface itself, represented by the monitor and mouse in the figure. (Manuals may be available, too, but they are getting smaller and becoming less of a factor.) Hence, the user interface had better also be isomorphic to the conceptual models of the designer and user.

Just as an isomorphism between user interface designer and user reduces mental translations, all other isomorphisms reduce mental translations. Thus, programmers benefit from an isomorphism (A in the picture) between the user interface and the
programming language, and database designers benefit from an isomorphism (B in the picture) between the programming language and the database. Isomorphism A comes from an object-oriented language into which the programmer can translate the objects from the conceptual model. Isomorphism B comes from an object database system, into which the programming objects may be directly stored.

At least that is the theoretical ideal. Nowadays, all these isomorphisms are feasible— and desirable—except for the database isomorphism. The database solution for a problem is sometimes an object database, but the decision depends on a host of practical considerations: scalability, performance, distribution, transaction size and frequency, and the presence of legacy data. For example, in large-scale business problems, the database solution often necessarily involves an existing relational database management system.

Isomorphism brings us full circle, back to objects. Isomorphism means that the conceptual models of the user and designer have the same form; the user interface evokes this shared model; and the programming model and wistfully, the database model, are faithful to it. Metaphors help us impart our conceptual models to each other, but we cannot program in metaphors. So we use the universal language of objects to express our metaphors in a form that object-oriented programming can handle.

## 13.9 Summary

Designing a first-class user interface is orders of magnitude more difficult than most people think. If we had a prescription for success, many more of us would be great user interface designers, and many more great user interfaces would be on the market. Unfortunately, great user interfaces are rare. In particular, we have seen that they can appear only in conjunction with great overall designs. No user interface can compensate for a poorly designed application.

Although we have no prescription for success, we know of some considerations without which failure is certain. The user interface designer must:

* Construct coherent conceptual models.

* Identify and develop use cases.

* Apply metaphors wherever practical—to facilitate learning and use of the user interface or to describe conceptual models.

* Use magic judiciously, to go beyond the metaphors in ways that do not clash with them.

There is no special order to these steps. We have to do them all repeatedly before they converge to a product.
You practiced these steps in the exercise on page 151. Given enough time, you would study usability too: observing users at work; presenting crude early mockups of windows to them for their feedback; and, once working prototypes are available, measuring the time for them to complete tasks.

In real projects, the difficulty of user interface design, indeed application design, is compounded by the often conflicting requirements placed on the application by different groups of users. Each group does things in its own way, or deals with its own cross-section of the objects, or sees the business from its own standpoint. Conflicting conceptual models are all around. This cacophony of demands makes it even harder to produce a coherent overall conceptual model and a first-rate user interface.

For a comprehensive treatment of the problem of designing user interfaces, see the book by Dave Collins [Collins 1995], which amplifies the theme only touched upon here, namely that a good user interface design is inseparable from a good system design. For the pervasiveness of metaphor in human cognition, see [Lakoff and Johnson 1980]. For several excellent essays on metaphor in user interfaces, see [Laurel 1990]. Two essays in that volume that challenge the value of metaphor are [Nelson 1990] and [Kay 1990]. The former is a diatribe against excessive use of metaphor and the latter emphasizes magic in overcoming the limitations of metaphor.

We have seen conceptual models that are metaphors, or definitions, or pictures. Here is one final example, from Nobel physicist Richard Feynman's perspective on physical laws: "A philosophy, which is sometimes called an understanding of the law, is simply a way that a person holds the laws in his mind in order to guess quickly at consequences" [Feynman 1967]. His "philosophies" help physicists anticipate experimental outcomes in precisely the same sense that coherent conceptual models help computer users anticipate the behavior of applications. Feynman's "philosophies" are yet another kind of conceptual model.

This chapter concludes our three-chapter tour of user interfaces. We turn next to the essential subject of polymorphism.
CHAPTER 14

Polymorphism

One of object-orientation’s most vital properties is polymorphism. Polymorphism increases the extensibility and clarity of object-oriented code. It influences object-oriented design so much that many authorities treat it as a fundamental object-oriented principle, alongside the objects, classes, and inheritance we discussed in Chapters 1 and 2.

Polymorphism relates to several other ideas, including subtyping (Chapter 17), type-checking, and dynamic binding. We begin with dynamic binding, which is an idea that makes sense in either object-oriented or non-object-oriented contexts.

14.1 Dynamic binding

Alan Kay observes that postponing a decision until the last possible moment is one of the most fruitful and characteristic trends in the evolution of computing [Kay 1993]. Examples of postponement in computing history include linkers, relocatable pro- grams, and virtual memory. Another is dynamic binding, which postpones selection of an operation until execution time.

Most traditional languages, like Pascal and FORTRAN, don’t support dynamic binding: if you write foo(x) in those languages, the compiler (or linker) determines the exact function foo to be executed, then compiles the directions to find that function. If the program has more than one function foo, the compiler uses the rules of the lan- guage to pick one. When the program eventually executes, that one runs. 1

<footnote n="1">1 The special situation in languages like C or Ada where the compiler can pick among functions with the same name but different argument types, such as foo(3) for integers and foo("hi") for strings, is known as overloading. This is not an example of postponement because the compiler distinguishes the two functions by examining the argument types, long before the function executes. Overloading is emphatically not dynamic binding.</footnote>
Dynamically bound languages don't preordain the function that executes. Instead, the function is selected while the program is already running, from possibly many functions named `foo`. It is often impossible to select the function or method any earlier, as this example in Smalltalk, which is dynamically bound, illustrates.

```Smalltalk
aCondition
    ifTrue: [y := 3]
    ifFalse: [y := #(5 7 eleven)].
y printOn: someStream.
```

Smalltalk has numerous `printOn:` methods—classes often define their own `printOn:` method to customize the way in which instances print or display themselves in textual form. (Recall the exercise on rendering any object into text, on page 56.) If it happens that the "true" path executes, the `printOn:` that executes should be the one appropriate for 3; that is, for class `Integer`. If the "false" path executes, it should be the one for `#(5 7 eleven)`; that is, for class `Array`.

The Smalltalk compiler cannot preordain the choice, for it can't predict which branch will actually occur at execution time. This is dynamic binding—the ability to postpone selection of the specific `printOn:` method until execution time. The more interactive an application is, the more situations arise in which the compiler can't know the function in advance, and the more unavoidable such postponements are.

## 14.2 Dynamic binding enables...polymorphism

Newcomers commonly assume that dynamic binding must work by way of conditional code that selects among the candidate methods, and is necessarily slow. Not always. The presence of conditional code and the speed of method selection depend on how a particular language system—the compiler plus the runtime environment— implements dynamic binding. Today's Smalltalk implementations are fast, and the different technique that C++ employs is even faster. (We'll see in Chapter 16 how C++ gets this speed by foregoing conditional code entirely.)

Here is one way to do dynamic binding. This technique is sometimes used in non-object-oriented languages, but we will see that it is unsatisfactory for object-oriented ones. Suppose your application has a user interface that will show each item in a mailbox. The items or "objects" could be memos, spreadsheets, or documents. You could use a conditional statement like `CASE`, `SELECT`, or `SWITCH`, depending on your language:

```Smalltalk
case y.type of
    m: showMemo(y) |
```
```pascal
s : showSpread(y) |
d : showDocum(y)
end;
```

This is Pascal, but the same style works in any language, as long as the "type" information is available along with the "object" at the time the program executes. In this example, the programmer would have to build and maintain the extra "type" field. Now, if you can do it in non-object-oriented languages, you can also do it in object-oriented ones. Moreover, in Smalltalk the type or class of y is readily available just by sending the message y class. Nonetheless, Smalltalk or not, this is an awful way to do dynamic binding, for the following reasons.

First, performance. On many computers, conditional branches, especially those with many cases, are slower than straight line code. (Branches are less of a drawback nowadays on most RISC computers, because they can pre-execute code ahead of a branch while they evaluate the branch condition.)

Second, and more serious, is an engineering drawback. Sooner or later you'll want to extend the application to accommodate other kinds of objects—changing and enhancing software is inevitable. Let's say graphics could now show up in the mailbox, too. You would have to alter the case statement to accommodate another case (g: showGraphic); that much is unavoidable. Furthermore, if the same case statement occurs elsewhere, for example to show the items in a file folder, each such occurrence must be repaired, too. But the case statement is much more insidious than that. Not only do you show items, but you are also likely to mail them, or print them, or save them, or execute or read them. These operations involve nearly the same case statement, each of which must be altered, too. Searching for and altering all those statements is tedious and error-prone.

We would like to avoid having to repair client code—the code that uses our spreadsheet and memo objects—every time we add a new kind of object to our library of reusable components. We are willing to concede that adding graphics objects necessitates new library code, namely the Graphics class, but we hope that client code can benefit from these new objects without incurring widespread alterations.

The solution to this problem in Smalltalk looks like this:

```pascal
y showIt
```

That's all. If you now add a class of graphic objects to your application, this line of code doesn't change. If the line occurs at several points in the client code, none of those occurrences changes, either. And if a similar line of code occurs to mail, print, save, execute, or read objects, those occurrences don't change, either. We have liberated client code from conditionals and in so doing immunized it against a whole category of invasive alterations.
Does the conditional really disappear? You may suspect me of merely factoring the noxious conditionals out of the client code and into just one conditional hidden inside a single **showIt** method. That approach is indeed possible. But it makes for a complex **showIt** method and is still one error-prone conditional too many. It is unnecessary and undesirable.

Here's how the object-oriented design works without any conditional at all. There are really *several* methods, all with the same name, **showIt**, one for each class of objects we're interested in: spreadsheets, documents, graphics, and so on. By asking the variable `y` to **showIt**, we are really asking the object that happens to lurk under `y` to **showIt**:

<figure><img src="image_88.png" /></figure>

Whatever kind of object that is, it responds directly with its own **showIt** method. There is no type testing and no branching. The running program doesn't even know what kind of object is there, and it doesn't care. It just trusts that the object understands **showIt**.

The fashionable name for this conditional-free style of programming is *polymorphism*. "Poly+morphism" is of Greek origin and means, "multiple+form." The variable `y` assumes "multiple forms," depending on the kind of object it happens to point to. Each kind of object administers its own **showIt** method, and so the response to the message `y showIt` effectively also assumes "multiple forms." Polymorphism—multiple forms—is a way to replace conditionals by classes, resulting in code that is easier to read and easier to modify.

## 14.3 A word on terminology

The concept of dynamic binding in object-oriented systems has two aspects: determining the object (and its type) and, having done so, looking up its chain of superclasses for the method. The latter often also goes, aptly and unambiguously, by the name *method lookup*. I use "dynamic binding" in the broadest and loosest sense, to
cover both aspects. Many authors limit "dynamic binding" to one or the other; that is, either to type selection [Booch 1991] or method lookup [Meyer 1988; de Champeaux et al. 1993].

You can think of dynamic binding as a mechanism for postponing method selection, implemented in different ways by different object-oriented languages. Polymorphism, although it requires a dynamically bound language, is not a mechanism but a design technique for improving the clarity of our software. The relationship between polymorphism and dynamic binding is a striking example of the inseparability of design from implementation. You can't design polymorphically unless your language supports dynamic binding.

## 14.4 Exercise: polymorphism

* Suppose an importer wants to calculate the tariff on the motor vehicles she imports. Suppose her software must apply different calculations, depending on whether the vehicle is a truck or passenger car. What should the high-level design look like? Think of two designs.

## 14.5 Solutions and discussion

**Solution 1.** Define an abstract class Vehicle, and two concrete subclasses, Truck and Car. Define a method `Vehicle->tariff` that does nothing. We called such a method "pure virtual" or or "subclassResponsibility" on page 64. Then define methods `Truck->tariff` and `Car->tariff` that apply the respective calculations for the two kinds of vehicles.

<figure><img src="image_89.png" /></figure>

**Solution 2.** Define a class Vehicle with an instance variable named `type`. The method `Vehicle->tariff` has the form:

```perl
type = 'truck'
ifTrue: ["truck calculation"]
ifFalse: ["car calculation"]
```
Object-oriented developers invariably think of the first solution first. People without object-oriented training, however, have recourse only to the second, which is actually not object-oriented. By now you know the drawback of solution 2: it is harder to maintain `if` and when other kinds of vehicles like motorcycles with different tariff calculations appear on the scene.

To summarize: The polymorphic, object-oriented design is extensible because the client code consists solely of:

```python
v tariff
```

This line of code doesn't change, even if motorcycles are imported. Polymorphism uses classes instead of conditionals to solve the problem.

## 14.6 Exercise: Smalltalk's if-less-ness

Consider any code that sends the `ifTrue:ifFalse:` message, such as this sample:

```python
X := ...
...
X ifTrue: ["true path"]
    ifFalse: ["false path"]
```

Think about the following questions without looking at any Smalltalk browsers. Then use a Smalltalk browser to verify your answers.

* In what class should the method `ifTrue:ifFalse:` be?

* What should the method `ifTrue:ifFalse:` do? In particular, should its code be conditional? And how many `ifTrue:ifFalse:` methods are there?

## 14.7 Solution

A plausible first guess for a class that implements `ifTrue:ifFalse:` is class `Boolean`. But the browser shows no such method:
<figure><img src="image_90.png" /></figure>

A closer look at class **Boolean**, however, reveals two subclasses named **True** and **False**. Examining class **True** first, we find among its methods an `ifTrue:ifFalse:`. Now, one might well expect to see some conditional code in the body of this method. But there is none:

<figure><img src="image_91.png" /></figure>

The evaluation of the `trueAlternativeBlock` is *unconditional*. That's because the receiver of the message, knowing itself to be the **true** object, has no need for the message's `falseAlternativeBlock`. A **true** object ignores the false alternative and simply executes the **true** alternative.

Now, class **False** has a totally different method, albeit also named `ifTrue:ifFalse:`. The logic within *that* method unconditionally executes the `falseAlternativeBlock`. After all, the **false** object knows full well that it has no need for the **true** alternative and summarily ignores it.
This situation seems paradoxical, at least on a superficial first glance. How can something as ostensibly conditional as a method named `ifTrue:ifFalse:` in fact execute no conditional code? The answer is exactly the same principle the `tariff` methods illustrated in the earlier exercise: subclasses can replace conditionals, as long as each subclass supports its own version of the method. Smalltalk just takes the principle radically far, down to the level of boolean objects.

## 14.8 Summary tip

As a rule of thumb, think twice about conditional statements in your code. Many of them may be opportunities for subclassing and polymorphism. "IF" statements disquiet object-oriented programmers. Unless you are certain never to expand them with additional cases, you should be as suspicious of them as you are of the "GOTO" in conventional programming.

## 14.9 Commentary: performance

Performance is a peculiar topic. The things that people dispute heatedly and at great length are often the ones that matter least. Usually they are the things that are easy to measure—how many conditionals, how many levels of address indirection, a highly specialized benchmark, and so on.

What really matters—when static SQL can be an order of magnitude faster than dynamic SQL, or when searching a queue from the rear instead of the front can halve CPU time, or when a working set size exceeds virtual memory—isn't so easy to measure. Instead, these are matters for savvy design. The savvy designer grasps the problem at hand and has a mental arsenal of alternatives to apply to it, plus an intuition born of experience to weigh their trade-offs and anticipate which is best and by how much.

Keeping these caveats in mind, what are the performance implications of polymorphism in object-oriented languages? Its measurable effect reduces to the net of two opposing forces:

1. Fast: replacing conditionals by defining new subclasses.

2. Slow: method lookup. Looking up an inheritance hierarchy for the class that implements a method, no matter how fast, is still slower than calling a function whose location is known at compile time. The techniques that language implementors use to achieve acceptably fast lookup are covered in Chapter 16.
The danger with cold calculations of these forces is that they are likely to distract us from the main event. Polymorphism above all contributes to cleaner systems that are more mentally tractable. And designers can understand tractable systems and hypothesize ways to improve their performance. You can't write faster code unless you can understand it.

Benchmark experiments on early versions of the CHOICES operating system, developed in C++ at the University of Illinois, showed that it performed unfavorably against UNIX. A year later, benchmark results showed CHOICES to be consistently superior to UNIX. The developers cited two reasons for the improvement. The first was that performance bottlenecks were easy to fix because they were encapsulated—hardly a surprise, for encapsulation is the most flaunted of object virtues. The second was replacing conditionals by subclasses—polymorphism can improve performance.

## 14.10 Commentary: Smalltalk, C++, and type-checking

The expression *type-checking* means to try to detect occasions when an object is being used in circumstances that are appropriate only for objects of other types or classes. (Remember that we don't distinguish between the words *class* and *type*; that is, not until Chapter 17.) Sending a message to an object that doesn't understand it is a typical example of an error that object-oriented languages type-check:

```
Whale new + 2.71828
```

Because **Whale** instances do not understand arithmetic messages like `+ 2.71828`, Smalltalk will inform us of this type error with a walkback.

The type-checking rules in C++ and Smalltalk are quite different. Consider these Smalltalk statements:

```
R := Rectangle new.
T := Triangle new.
R := T.
```

Smalltalk variables like `R` and `T` point to objects. They have no allegiance to any specific type (class); they can point at one moment to an object of one type and at another moment to an object of a completely different type.
<figure><img src="image_92.png" /></figure>

The assignment statement `R := T` just switches `R` so that it too points to the triangle object. This is not a type error in Smalltalk.

Contrast this with the analogous situation in C++ (The assignment syntax in C++ is `r = t;`):

```
Rectangle *r;
Triangle *t;
...
r = t;
```

The C++ compiler, recognizing that variables `r` and `t` have been declared for different, presumably incompatible classes, detects right away that the assignment is an error. In effect, the type of object that a variable like `r` (or `t`) may point to is fixed once and for all by the compiler. Hence, any code that tries to use the variable for another type of object won't even compile.<fnref n="2" />

If you take this restriction literally—that C++ fixes the type of object that a variable can hold or point to—then you may wonder whether the polymorphic mailbox example illustrated on page 161 works in C++. In other words, you may worry that the variable `y` in `y showIt` (or in C++ syntax, `y->showIt();`) is constrained to just one kind of object. Fortunately not. In C++, if you declare `y` to be a pointer to objects of

<footnote n="2">² The C++ policy of detecting type mismatches early appeals to our instinct for safety. On the other hand, safety comes at a price. A program written in a language like Smalltalk where variables are untyped is quicker and easier to modify, and more flexible because its variables can accept more types of values. The debate for and against early type-checking is exhausting, emotional, endless, and rarely profitable to linger on. Suffice it to say that C++ and Smalltalk represent opposite poles in the debate, both with good reasons. Safety is important, and so too is flexibility.</footnote>
type T, then the compiler will also allow y to point to objects of the subtypes of T! This is a remarkable, but intuitive and natural feature of the language. It says that it makes sense for a shape variable to refer to a rectangle object (or a triangle, or...). But the converse would be silly: to expect that a rectangle variable could refer to an object of any shape.

Similarly, an insect variable ought to be able to refer to any butterfly, but a butterfly variable ought not to be able to refer to an arbitrary insect. That's how object-oriented languages like C++ and Eiffel and Java work: a variable can point to objects of any of its subtypes, but it can't point to an object of its supertype(s).

Here's a concrete C++ example. First, declare rectangles and triangles to be subtypes of shapes, and (details omitted) supply various methods that override do-nothing methods in the shape superclass. These methods might calculate area or perimeter, for example.

```cpp
class Rectangle : public Shape { ... }
class Triangle : public Shape { ... }
```

Next, declare variables of each of these types, and (details again omitted) make r and t point to a rectangle and triangle object:

```cpp
Shape* s; Rectangle* r; Triangle* t;
...
```

Either of the following assignments is legitimate—an insect can refer to a butterfly:

```cpp
if (...) s = r;
else s = t;
```

On the other hand, an assignment like `r = s;` would be forbidden by the compiler—a butterfly can't refer to an arbitrary insect. Next, ask for the area of `s` with this message:

```cpp
answer = s->area();
```

Which area method executes, the one for rectangles or the one for triangles? The right one. That is, assuming certain C++ niceties are observed in declaring `area()`, the area method for whatever `s` actually points to executes: if the conditional is true, then `s` points to a rectangle, and `Rectangle's area()` executes; if the conditional is false, `s` points to a triangle, and `Triangle's area()` executes.

That's how C++ supports polymorphism, as a compromise between the flexible dynamism of Smalltalk and the rigid safety of traditional type-checked languages. The same approach is used by other object-oriented languages—Eiffel, Java, Modula-3... —that oblige the programmer to declare types for variables. Smalltalk differs from all these because there is no way to declare a type for a Smalltalk variable; any variable can refer to any kind of object.
## 14.11 Commentary: the tomato in the mailbox

Suppose you're handling your postal mail. You discard the bulk mail, but you open your packages immediately. This is a fairly ordinary object-oriented problem. The polymorphic solution is to design a **Mail** supertype of both **Package** and **BulkMail** and write appropriate **handleMail** methods for each kind of mail. As we know, this solution sidesteps the need for runtime type testing ("if the object's type is **BulkMail**, then... ").

You can't always sidestep runtime type testing, however. Suppose you find something in your mailbox that isn't an instance of a subtype of **Mail**, say a garden-fresh tomato from your neighbor. Does this problem have a polymorphic solution?

In C++, the answer is no. Polymorphism works only for types that share a supertype. Other than inventing an artificial supertype of both **Mail** and **Tomato**, your only recourse is for your program to ascertain at execution time that the object is a tomato and not mail, then send it a valid **Tomato** message. This difficulty motivated the ANSI C++ committee to add runtime type testing to the C++ standard. (See [Lea 1992] for practical uses of this feature.)

Contrast the situation with Smalltalk. Polymorphism works for tomatoes and mail, even though they are in unrelated parts of the class hierarchy. In other words, if you write a **Tomato>>handleMail** method that eats the tomato, client code like `y handleMail` works fine, whether `y` points to a package or a tomato. The Smalltalk variable `y` isn't constrained to any specific type(s). The Smalltalk developer doesn't need runtime type testing to solve this problem.

We can describe the polymorphism that Smalltalk supports—and C++ doesn't—as *implicit polymorphism*. People also refer to it variously as *ad hoc*, *signature-based*, or *apparent polymorphism*. This is a concept on which the terminologists have not yet had their last word. Implicit polymorphism is polymorphism that works for types of objects that may not share supertypes; explicit type relationships aren't necessary. It's polymorphism *across type hierarchies* instead of *within type hierarchies*.

Ordinary polymorphism—polymorphism within explicit hierarchies—is sometimes called *inclusion polymorphism*. The rules for any variant of polymorphism amount to the way in which a language determines whether it is okay to substitute instances of one class for instances of another. These rules have to do with measuring consistency between classes, a matter I'll tell you more about in Chapter 17.

To sum up, C++ supports only *inclusion polymorphism*, while Smalltalk supports both *inclusion* and *implicit polymorphism*. Where *implicit polymorphism* is necessary, the C++ developer reverts to runtime type testing. Thus, the need for runtime type testing is greater in C++ than in Smalltalk because of the absence of *implicit polymorphism* in C++. Ironically, Smalltalk makes runtime type testing easy (send any object the message *class*), but requires it less often. In any language, you should use runtime type tests
sparingly. (Again, see [Lea 1992].) They are apt to introduce hard-to-maintain conditionals and are antithetical to the object-oriented style of programming.

* To emphasize this point one final time, decide whether this sample use of runtime type testing is desirable (Hint: it is not.) and what you would do to rectify it:

```
mailbox do: [ :m ]
    m class = BulkMail
    ifTrue: [ m discard].
    m class = Package
    ifTrue: [ m open].
    m class = Tomato
    ifTrue: [ m eat]
]
```

## 14.12 Commentary: multi-methods

Sometimes, the orthodox object model is not enough. For some problems, it is just awkward to conceptualize the solution as a method on an object. Sometimes a behavior involves two peer objects, and neither one particularly merits having sole responsibility for the behavior. For example, why model a dancing couple by writing a method on one favored partner that accepts the other partner as an argument? Wouldn't it be more natural to write a *multi-method* on both partners? Of course, there is no such thing as a multi-method in most object-oriented languages, including Smalltalk. The only commercial language with multi-methods is CLOS. What then do you do instead when confronted with this kind of problem?

The answer is a technique first published by Dan Ingalls [Ingalls 1986]. First, designate one of the dancers, say x, as a preferred target. Send it the message *dance*: y, passing along the other object, y, as an argument. Now, x will need the help of behavior on y, and so it redispatches a message *danceX*: x to y to invoke this behavior, passing itself as an argument, as illustrated here:
<figure><img src="image_93.png" /></figure>

Note that we allow the two dancers to belong to different classes. Nothing prevents two disparate dancers from dancing, for example if X is BalletDancer and Y is Swing-Dancer. Also, don't overlook the significance of passing self as an argument to y: not only is y getting control, but y is getting full access to x. Thus, the objects x and y are as intimate as object-orientation lets two objects be.

Now, none of this discussion so far has a very polymorphic feel; it only conveys a strong sense of alternation of control, plus object-oriented intimacy. Polymorphism happens when we let a variable range over objects of different types, and we haven't considered that possibility yet. So let's add some variability. We could let either x or y vary, but to make things interesting, we'll let them both vary. We must then generalize the preceding sketch:

<figure><img src="image_94.png" /></figure>

<figure><img src="image_95.png" /></figure>

<figure><img src="image_96.png" /></figure>

<figure><img src="image_97.png" /></figure>
The message flow is the same as before—it starts with x **dance**: y and proceeds with a redispatch to y of a message of the form **danceX**: x. Only now we see four variations in which this dance may play out. But the implementation uses *no* conditional statements! We have an example of *multiple polymorphism*, where both the receiving variable x and the argument variable y are independently polymorphic, because either can refer to an instance of two classes.

Because the alternation of control resembles what occurs in a classical pas de deux, where the dancer and ballerina take turns upstaging each other, I call this object-oriented arrangement a *pas de deux* or a *duet*. But the name that occurs most often in the literature is *double dispatch*. By whatever name, this arrangement occurs widely in object-oriented systems, and is discussed again as a pattern in Chapter 18.

As a final aside, let's contrast multi-methods with the runtime type testing discussed earlier. Because C++ has traditional functions as well as methods, we could use a function of the form `dance(x, y)`, thereby more faithfully portraying the symmetry between the two real-world dancers. And because the C++ standard supports runtime type testing, this `dance` function can consist of `if`-statements like:

```cpp
if ((BalletDancer*)(x) && (SwingDancer*)(y)) wild_combo(x, y);
```

which means, "if x is a ballet dancer and y is a swing dancer, then have them dance a wild combo." We would add a similar `if`-statement for every combination of dancer types that we cared about. This technique is an alternative to the double dispatch solution of dancing outlined above.

The symmetry of the function `dance(x, y)` in this approach is more attractive than double dispatch, which depends strongly on arbitrarily favoring one partner or the other. The runtime type tests, however, expose maintenance programmers to the instabilities of conditional code, which we have sought to avoid throughout this chapter. Moreover, the symmetric solution is not even possible in Smalltalk. Smalltalk has methods only. Therefore we must designate one dancer or the other as the primary object to carry the dance responsibility.
CHAPTER 15

Practicing polymorphism

Understanding polymorphism, which was our purpose in Chapter 14, is not as valuable as being good at applying it. This chapter is an opportunity for you to design an object-oriented, polymorphic solution to a real problem. This is the problem of undoing a user's actions. First, we need an application.

15.1 Design exercise I: a shape editor

Consider a simple application that lets the user create, move, or remove shapes. The kinds of shapes won't affect the overall design much, so let's agree to limit them to circles and squares. This application is a foundation for many families of commercial applications—graphical editors and simulators, network management tools, CASE tools, and video games.

□ Use CRC cards to brainstorm about the essential classes and their responsibilities. Brainstorming works best as a social act, in a group of two to four peers. Hints:

* Stick to the model. In other words, don't worry about the look and feel, or "view," of the application. This is largely an exercise in disciplining yourself to prevent the user interface from influencing your design. Design only the essential underlying classes—those which will work with any view at all.

* Don't forget that container objects are ubiquitous in the everyday world, and are therefore likely to insinuate themselves into even a small design like this one.

* If you find fewer than three classes, you definitely don't have enough to describe the application in an object-oriented way. If you can't find enough classes, try
resorting to the trick of looking for nouns and verbs in the problem statement. Nouns may signify objects and verbs may signify responsibilities.

* Finding too many classes is just as undesirable. If you find more than about six, you're probably obscuring the essence of the design.

## 15.2 Solution and discussion

I will discuss the ideas that students typically try as they work toward a solution, following the same order in which they try them.

The most obvious CRC cards are ones for Circle and Square objects. It is also not much of a stretch to anticipate that an abstract superclass named Shape might be handy for gathering common expectations of circles and squares. For example, if we expect both circles and squares to be capable of movement, we can record that responsibility in the Shape class. Imagining further how we might eventually move a shape, we might even allow for an instance variable that captures the position of each shape instance. Our CRC cards would now resemble:

<figure><img src="image_98.png" /></figure>

Instance variables specific to Circle and Square appear on their respective cards.<fnref n="1" /> Because the application is supposed to "create, move, or remove" shapes, it is tempting to add "creating" and "removing" responsibilities to the Shape "doughnut" above; almost everyone considers this. However, I advise against adding either one, for these reasons:

<footnote n="1">¹ Orthodox use of CRC cards does not plunge to the level of instance variables. I use them here to indicate the way toward implementation a little further than is customary.</footnote>
First, creating an object is not the object's responsibility. An object that doesn't exist yet can hardly create itself. Rather, as we have seen, creation is a responsibility of the object's class, by means of something like a new method. It is fine to write down this responsibility for creation, but not on the doughnut that represents an instance. Write it somewhere else, like the upper-right corner of the card, or the reverse side.

Second, writing "removes itself" on the Shape doughnut (or the Circle or Square doughnut) is disagreeable for two reasons. First, you are metaphorically asking the object to commit suicide, and programming objects don't want to do that any more than real objects do. Second, the expression "remove itself" implies a place from which the object is to be removed—remove it from *where?* We need to put our finger on this place.

According to the second hint, we need a container object. If you remove flowers, you remove them from a vase; if you remove books, you remove them from a library, or a bookshelf. What shall we call the container that holds our shapes? A common but undesirable answer is Window. A window suggests a user interface, and we do not want our design to be biased by user interface or view considerations. We want to emphasize the model aspects, so we need a more neutral word. I suggest ShapeRoom; you can probably do better, but ShapeRoom is good enough for us to proceed.

This container for the shapes is a handy place for recording several responsibilities: holding shapes, removing them, adding them, even moving them. The CRC card for this class now looks like the one on the right. This class is a talented container; it supports ordinary container-like responsibilities, but also somewhat more, like moving shapes within it. It does what we would expect of a shape editor; ShapeEditor could well be another name for it. An instance of this class—a model—will process messages from the user interface—a view.

<figure><img src="image_99.png" /></figure>

Notice that the instance variable named contents suggests how ShapeRoom will fulfill its container-like obligations: this instance variable should refer to an instance of class OrderedCollection, or perhaps Set. In other words, a ShapeRoom buys an ordinary Smalltalk collection to hold its shape objects.

Also notice that "moving" appears on the card for ShapeRoom as well as the card for Shape. A ShapeRoom receives a message to move a specific shape to a specific point. The method in ShapeRoom that performs this function in turn sends a message to the specific shape to move itself to the specified point. This arrangement isn't unusual—a high-level move method on ShapeRoom collaborates with a lower-level one on Shape to get its job done.
Next, let's take a moment to review the topic of the previous chapter, polymorphism. Consider the presentation of the shapes on the user interface. This is nominally a responsibility of the view classes that I said we would not design here. Nevertheless, model classes must cooperate by making information about themselves available to view classes. We can call this responsibility of shapes "rendering." Each kind of shape will render itself in a way appropriate for itself; hence we should expect circles to render themselves differently than squares would. A view will not know or care whether a shape is a square or circle; it will simply trust the shape to render itself acceptably.

Thus, class Circle and Square will each have a method named, say, render, and class Shape will have a subclassResponsibility method with the same name. Shape>>render documents the obligation of each subclass to support rendering, but itself does nothing. As the application evolves, and additional classes of shapes emerge, each will require its own render method. In other words, shapes are polymorphic. Here, as in the examples of the last chapter, client code, in this case a view, will not be affected by introducing new classes of shapes.

## 15.3 Design exercise II: undo and redo

Now that we have an application, this simple shape editor, we want to make the user's actions undoable. Undo means reverting an interactive application to an earlier state. An application with strong undo support motivates users to explore unfamiliar features and provisional streams of thought because they know they can always revert to their point of departure if things turn out badly. If an application also lets its users redo what they've undone, so much the better. A few years ago it was unusual for interactive applications to support undo, let alone redo. Today, the opposite is true: almost all new applications support undo, albeit to varying degrees. But once you have been spoiled by an application with unlimited undo-redo, anything less is an anachronism.

* Design an enhancement to the shape editor that lets the user undo any number of his most recent actions. If possible, brainstorm with CRC cards and a small group of peers. Hints:

* A good object-oriented solution will handle multiple undos as well as it handles one undo. You might as well aim for unlimited undo. Don't get sidetracked into worrying about redo yet. After you solve unlimited undo, unlimited redo is a small extension.

* As always, if you have trouble getting started, look for nouns and verbs. They are especially telling in this problem.
* Four to seven classes is a good range for describing the solution. The number depends on the original application. It therefore pays to review the shape-editor exercise.

* You will need another appropriate container class.

## 15.4 Solution and discussion

The solution is an object-oriented classic; it also works for other interactive applications. It appeared early in the 1980s in the MacApp framework for Object Pascal developers, and proliferated thereafter. It has even achieved the status of a design pattern (Chapter 18).

The key to discovering the solution is the clause, "undo...actions" in the problem statement. Here, "actions" is a noun (!), and nouns are always plausible aspirants for objects. The verb "undo" then looks like a promising responsibility of an action object—actions should know how to undo themselves. Once you accept this much, unorthodox as it may at first seem, you have little choice but to sketch a card like the one on the right.

<figure><img src="image_100.png" /></figure>

The trouble is that an action is a pretty nebulous idea, and so this card isn't very satisfying. That's where the original, concrete problem comes in. The shape editor had exactly three functions: create, move, and remove. Each of these is an action that the user may want to undo. That gives us three kinds of undoable actions or, in other words, three subclasses of Action. This is a perfect setup for an abstract class and three concrete subclasses:

<figure><img src="image_101.png" /></figure>

* = pure virtual, subclassResponsibility
info2 = information needed to undo myself (a move)
Undoing is a subclassResponsibility of the superclass—it does nothing—but a concrete responsibility of the three subclasses, each of which carries it out in its own way. They will retain any information (in the form of instance variables) they need to carry out their mission. For example, the only way a Move object can have the wherewithal to undo itself is if it knows the shape instance being moved and the position from which it came. Thus the information inside the Move instance pictured above consists at least of instance variables representing a shape and the shape's original position. (Look for these instance variables when you work with the code in the next section.)

To understand the life cycle of these action objects, imagine a sample scenario: move a circle, then move it again, then undo both moves. Each move will result in a separate instance of the Move class. These two instances must be stored in order, then recalled and undone in reverse order. A container of some kind is evidently needed, and because of the order reversal, a stack seems eminently suitable. Thus whenever the application moves the circle, it instantiates a Move object and pushes it onto the stack. When the user calls for one or more undo's, the application pops the Move objects off the stack one by one, and asks them to undo themselves. The Move objects are able to comply because they know the circle and its previous position. Summing up the design:

<figure><img src="image_102.png" /></figure>

One loose end remains: how do you attach this design to the design of the original editor? Not much changes. The implementation of the "move a shape" responsibility of ShapeRoom must now instantiate a Move object and push it onto the stack. Similarly, the "add" and "remove" responsibilities of ShapeRoom instantiate Create and Remove objects, respectively, and push them onto the stack. ShapeRoom gets one additional responsibility, "undo." ShapeRoom carries out its "undo" responsibility by popping the top action from the stack, whatever the action may be, and asking it to undo itself.

Notice the implications of the clause, "whatever the action may be:" this is another polymorphic design. The room doesn't know and doesn't care whether the popped action is an instance of Create, Move, or Remove. For that matter, the room doesn't care what kinds of actions reside anywhere in the stack; it trusts only that they know
how to respond to requests to undo themselves. Even if you should later extend the
application with additional kinds of actions, the room won't care—not one jot of its
code changes. This is an archetypal example of polymorphism's value.

Inexperienced designers usually feel tricked that something so verb-like as "move" turns out to be an object. Sometimes they feel that the solution is contrived. After all, in the original shape editor, "move" was a responsibility—more akin to a method than an object. That analysis remains correct and valid. It's simply irrelevant for the present problem—the undo problem has only a superficial relationship to the editor problem. The editor problem was about manipulating shapes, and so we designed shape objects. The undo problem is about manipulating actions, so we design action objects. Because actions are at the heart of the problem, they become the leading candidates for classes. The problem has shifted from shapes to actions, and the designer's attention had better shift along with it.

Finally, remember that real designs proceed in fits and starts and rarely arrive
smoothly at a neat conclusion. Thus, a team of designers working on this problem for
the first time should have hit a few dead ends and scratched out and discarded quite a
few CRC cards along the way. Good design derives from failure.

15.5 Implementing undo

□ Build a stack class named **StackBuy** by buying from class **OrderedCollection**. If the stack is empty, make **pop** return the **nil** object. If necessary, review the stack designs on page 100. Test **StackBuy** until you are confident that it works correctly.

□ Build a stack class named **StackInherit** by inheriting from class **OrderedCollection**. Ideally, **StackInherit** and **StackBuy** should behave identically. That is, although their internals differ, a user or client shouldn't know the difference. (But remember the tradeoffs discussed on page 102. In Smalltalk, some behavioral differences are unavoidable.) Test **StackInherit** also.

□ The code you are about to work with requires application CwExamples to be in your image. IBM provides this application with either the Standard or Professional product. (If you are using the Professional version and it does not appear in your Application Manager, pick the menu options *Applications > Available*, then select the CwExamples application. *Load* the most recent edition.)

□ Obtain the file **student.aps** from http://www.claritycomputing.com/books/sod/files.
This code implements a working shape editor, except that the undo feature is broken. File in the code by following these steps:
* Start from an Application Manager.

* Select any application. It doesn't matter which; any selection will activate the menus you'll need.

* Pick menu option *File In*.

* In the dialogue box, locate and select the file `student.aps`, and push `OK`.

Select the application `ShapesApp`, double-click on it to expose its subapplications, and select and browse the subapplications `ShapesModels`, `ShapesUndoSupport`, and `ShapesViews`. Answer these questions:

* What are the names of the two main methods in the action classes? Read their code to reassure yourself that they are simple yet will do the job.

* What class and method instantiates a `Move` object? A `Remove` object? A `Create` or `Add` object?

* Why does `Move` have a third instance variable representing the target position?

Try the class method `example` in both `TextView` and `GraphicalView`. What is the problem? Fix it, using class `Stack` in the `ShapesUndoSupport` application.

Verify that your own stacks, `StackBuy` and `StackInherit`, also fix the problem.

## 15.6 Summary

Most object-oriented solutions to this problem use the name `Command` instead of `Action`. By either name, this is one of the most exquisite applications of polymorphism in object-oriented design.

The solution is recognized as a design pattern, also called *Command* (page 217). Two noteworthy characteristics of the pattern:

1. *Small size.* The solution required dozens, not hundreds of lines of code.

2. *Minimal memory.* The application stores only the information indispensable for undoing (or redoing) an action. In many cases, like moving, this information amounts to just a few words of storage. By contrast, the non-object-oriented alternative that some people consider—saving the entire state of the application upon every action—consumes machine resources so rapidly as to render multi-level undo impractical.

This chapter completes your study of the object-oriented essentials. The rest of the book pushes into areas which beginners rarely see, but are part of the mental landscape of experienced Smalltalk developers.
CHAPTER 16

How object-oriented languages work

This is the first chapter in which we venture past the essential object-oriented princi- ples. We begin by dealing with how object-oriented languages actually work, deep down inside. We will see that the look and feel of a language is shaped by these inner workings.

At one end of the spectrum is Smalltalk, noted for its incremental development style, its handling of memory concerns for the programmer, and its reflectiveness. ( Reflectiveness or reflection is a software system’s ability to examine and modify itself on the fly.) These are all consequences of a runtime engine, also called the Smalltalk vir- tual machine, which controls execution of every message and monitors computing resources.

At the other extreme, C++ relies on a conventional compile, link, and execute cycle. It is faster at runtime than Smalltalk and it links readily to foreign languages, but the price is a sluggish development feeling and memory bugs that sorely test a pro- grammer’s mettle.

You don’t need to know the content of this chapter to program in Smalltalk or C++, but knowing it will go a long way toward explaining why your language and its environment behave as they do.

16.1 Virtual machines

A virtual machine is a synthetic computer. It behaves as a real machine would, if only there were such a machine. Because there isn’t, people use a virtual machine to emulate the one they wish they really had. Virtual machines are interesting only because of what they execute. For a Smalltalk virtual machine, that something is called the image .
The image consists of all the objects in your computer, both the ones you create and the ones Smalltalk already provides.

Because "everything is an object," the image contains unusual objects like compiled methods. That is, whenever you write and compile a Smalltalk method, Smalltalk's compiler produces an instance of the class CompiledMethod. Each of these objects consists of bytecodes, which are the machine instructions that the virtual machine knows how to execute.

A running Smalltalk system therefore consists of these two pieces of software—a virtual machine running on your underlying computer hardware plus an image running bytecodes on the virtual machine. This is really a familiar notion cloaked in a fancy name. An interpreter—a BASIC interpreter, or a Pascal p-code interpreter—is also a virtual machine. Instead of executing the bytecodes in a Smalltalk image, it executes some other language, like BASIC or p-code. Sometimes people even refer to the Smalltalk virtual machine as the Smalltalk interpreter.

The difference between Smalltalk's virtual machine and other, simpler virtual machines (or interpreters) is sophistication. The Smalltalk virtual machine does more than merely execute one bytecode after another. It also manages processing and memory resources, much as a full-blown operating system does.

By the way, one side-effect of this arrangement, or of any arrangement based on a virtual machine, is a technique for transporting applications between computer architectures. If Smalltalk runs on one computer architecture, we ought to be able to make it run on another by rewriting only the virtual machine. The image should run as well on one virtual machine as another. The industry's early learning experience with Smalltalk came about in just this fashion. Early in the 1980s, Xerox PARC released the Smalltalk-80 image, along with the specification for its virtual machine, so that any computer manufacturer could run Smalltalk-80 on their own hardware, merely by writing a virtual machine. In those days a basic virtual machine implementation could be built in about one programmer-year.

The situation is a little more complicated today because many modern images contain objects that are specific to the underlying operating system or windowing manager. These objects exploit specific features of the platform, and their presence guarantees that the image cannot simply be moved to other platforms. IBM Smalltalk overcomes this difficulty by encapsulating these platform-specific objects under a layer of objects that is standard across all its platforms. As we saw in Chapter 12, the layer for user interface objects resembles the Motif standard. The layer for file-system objects resembles another UNIX standard, known as POSIX.1. IBM Smalltalk code that adheres to these standards is then portable from platform to platform.
Smalltalk-80, now known as VisualWorks, preserves the old tradition best: its virtual machine encapsulates all of the underlying platform; this arrangement decouples the image from the platform. Smalltalk-80 images are therefore highly portable. But because they are oblivious to platform-specific widgets, user interfaces don't have the look and feel of the platform they are running on. (ParcPlace-Digitalk has stated its intent to base its combined VisualWorks/VisualSmalltalk offering on the Smalltalk-80 virtual machine.)

## 16.2 Method lookup

Method lookup, also called method dispatch, selects the right method to execute among all the methods in an object's class and superclasses. Smalltalk's virtual machine performs this task by way of a component known as the message handler (or dispatcher).

At the moment of each message, and no sooner, the message handler decides which method the virtual machine should execute. It cannot, as conventional compiled languages can, decide the method at compilation time. In fact, Smalltalk is such a dynamic system that Smalltalk code could modify methods, or add or remove them, at any time, even immediately prior to executing them. Thus, any message can potentially affect the environment of classes and methods in which subsequent messages execute. Conventional languages can't do this; it would be akin to recompiling and relinking changes to your program in the midst of executing it.

Now, one proposal for handling this last-minute lookup could be to store a dictionary of method pointers for each object, as illustrated here for an object of class Point:

<figure><img src="image_103.png" /></figure>

This hypothetical dictionary must be constructed carefully: if a method occurs in both a superclass and subclass, the dictionary entry should point to the overriding one in the subclass.
To resolve a message to this point instance, the message handler locates the message’s selector among the dictionary’s keys and executes the associated method. This proposal doesn’t solve the prickly matter of messages to the special variable **super**, which breach the normal lookup and may access overridden methods.

Moreover, this proposal imposes unnecessary bloat on every object. It burdens an object as lean as a point with pointers to all the methods of **Point** and its superclass **Object**. That’s many dozens of pointers, and they are all repeated over and over for each of possibly multitudinous point instances in an application. Clearly unacceptable. To remedy this problem, Smalltalk arranges matters in the following uniform way. (This is only a conceptual picture—the actual details vary between Smalltalk dialects. IBM Smalltalk for example conforms to the spirit but not the letter of this picture.)

<figure><img src="image_104.png" /></figure>

Each instance has just a pointer to its class. The class (**Point**) carries a dictionary of its (instance) methods, plus a pointer to its superclass (**Object**), which in turn carries a dictionary of its own (instance) methods. If there are more layers of classes in the hierarchy, the pattern repeats: each class object carries its own dictionary of methods, plus a pointer to its superclass. The dispatcher merely chases through the chain of dictionaries until it finds the method it seeks. If the method is absent from all the dictionaries, the familiar “does not understand” walkback appears. Notice the flexibility: the methods and the dictionaries may be altered at any time; the dispatcher dutifully chases through the current chain of dictionaries no matter how recently such alterations have occurred.

This approach minimizes storage consumption—each point carries its own private instance variables, plus one pointer to its class. But its performance is suspect—iterative searches up the chain would be intolerably slow. Smalltalk therefore resorts to two venerable performance tricks, caching and hashing. Hashing is a way to place each entry in a table at a magic offset that can be computed (“hashed”) directly from the entry. Because every entry then resides at a predictable offset, table lookups can
proceed directly by computing the offset at which an entry ought to reside. If the entry isn't at the offset, it isn't in the table. (I've oversimplified a little—hashing algorithms also have to handle the potential for collisions when the magic offset computed for two different entries is the same.) Because Smalltalk dictionary objects are designed with hashed lookups, instead of more naive binary or sequential lookups, search times are nothing like our worst fears.

Actually, searching through the method dictionaries is rarely necessary. Because a message that occurs once tends to recur in the near future, Smalltalk maintains a cache of recently sent messages, and the dispatcher looks in this cache first before beginning the laborious search up the superclass chain. The effect of a method cache is sizable. According to [Krasner 1984], an appropriate method cache can have hit ratios as high as 95 percent, decrease method lookup time by a factor of 9, and improve overall system speed by 37 percent.

Method lookup in C++ works without any kind of engine or dispatcher. It still relies on a table, called a *virtual function table* or *v-table*, for each class. But these tables are simply lists of pointers, not dictionaries with powerful lookup facilities as in Smalltalk. Imagine a music synthesizer application, where *Piano* and *Oboe* are concrete subclasses of the abstract class *Instrument*, and all instruments support methods (*virtual functions* in C++ parlance) to tune themselves (to some intonation and pitch) and to play (a note). The v-table for *Piano* looks like this:

<figure><img src="image_105.png" /></figure>

When the C++ compiler encounters a message to tune a piano (*piano->tune*() in C++ notation), it generates code to execute the function found by the first pointer in the v-table. If it encounters *piano->play*(), it generates code to execute the function found by the second pointer. The v-table is stable; unlike in Smalltalk, there is no prospect of introducing or removing methods at execution time. Thus, this generated code is unconditional; the compiler determines once and for all the location of the function to be executed. No dispatcher ever gets involved.

So far, this table is fairly unremarkable. The oboes, however, make life interesting. For *Oboe* also has a v-table, and it has exactly the same structure as *Piano's*. That is, its first pointer points to the tune function for oboe and the second points to the play function for oboe. The compiler carefully builds all v-tables for subclasses of *Instrument* in this parallel way.
Now consider a polymorphic variable *instrument*, which could point to *either a piano* or an oboe.

<figure><img src="image_106.png" /></figure>

Which of the two play functions executes in response to a message of the form `instrument->play()`? The right one. The C++ compiler, knowing that `Oboe` and `Piano` are subclasses of `Instrument`, has crafted the two v-tables to have a parallel structure— the function pointers are in the same order in both tables. When the compiler encounters the expression `instrument->play()`, it unconditionally generates code to execute the method found by the second pointer in the table—even though it is quite unable to anticipate what kind of object *instrument* will point to when the code eventually executes. If the object turns out to be a piano, the second pointer points to piano playing; if the object turns out to be an oboe, the second pointer points to oboe playing. Either way, the second pointer is the right one, and the appropriate function will execute.

Let's recapitulate the two salient points about method dispatch in C++: it works flawlessly without a runtime engine, and the executing code is free of conditionals. All else being equal, you should expect C++ programs to run much faster than Smalltalk programs. All else is rarely equal in the real world, though, and performance is never this simple.

As one example, two of my friends—one partial to C++ and the other to Smalltalk—got into a dispute about speed and settled it by benchmarking a loop of method dispatches. To the chagrin of my C++ friend, the Smalltalk code was just as fast. The reason? They happened to be using a 16-bit operating system in which the v-tables were in a different memory segment than the objects. As a result, segmentation faults occurred on every function call, and this overhead swamped the speed benefit of the v-table scheme. This is an unusual example, but it illustrates an important performance principle, namely that astute programming almost always matters more than the programming language does.