<<

Arguments and Results

James Noble

MRI, Scho ol of MPCE,

Macquarie University, Sydney.

[email protected]

Octob er 20, 1997

Abstract

If an ob ject oriented program is a collection of communicating ob jects, then the ob jects' pro-

to cols de ne the languages the program sp eaks. Unfortunately, proto cols are dicult to design

in isolation, so many programs' proto cols are not as well designed as they could b e. This pap er

presents six patterns which describ e how ob jects proto cols can b e designed or redesigned. By using

these patterns, programs and designs can b e made more simple, more general, and more easy to

change.

Intro duction

Ob ject's protocols, also knowasinterfaces, are very imp ortant in ob ject oriented design. An ob ject's

proto col is the face the ob ject presents to other ob jects surrounding it. Using an ob ject's proto col, other

ob jects in the program can use the ob ject as a server,thus accessing the b ehaviour the ob ject provides.

Similarly, an ob ject can act as a client to other ob jects, in turn using their proto cols to access their

services.

This pap er presents six patterns for designing ob ject oriented proto cols see Figure 1. The patterns

fo cus on two asp ects of proto col design | the messages ob jects can receive, and the results ob jects

return in resp onse to the messages. These patterns do not attempt to describ e novel techniques, rather,

they present well-established solutions for ob ject oriented design. These patterns should be useful

for intro ducing the techniques to novice programmers, and for more exp erienced programmers, should

illustrate when particular techniques are applicable and their relative strengths and weaknesses.

These patterns are interrelated, but they do not form a whole language. Rather, the patterns are

two fragments Patterns ab out Arguments and Patterns ab out Results whichmay one day form

part of a larger pattern language. Eachof the fragments has the same structure see Figure 2 with

one general pattern, and a couple of more sp eci c patterns which re ne the general pattern to handle

sp ecialised contexts. Figure 2 also illustrates two relationships between the patterns. One pattern

can re ne another pattern, meaning one pattern is a more sp eci c version of the other. Alternatively,

patterns can con ict, meaning that the patterns are mutually exclusive, each providing a di erent

solution to a similar problem [26].

Forces

Each of these patterns resolves a numb er of di erent forces, and some con icting patterns resolve similar

problems in di erentways. Many of the patterns consider the ease of reading or writing of a particular

solution | generally, solutions which are easy to write are more likely to b e chosen by programmers,

and solutions which are easy to read are likely to b e easier to maintain. Since smaller, simpler programs

are generally easier to read and write, the patterns are concerned with the complexity or size of a design,

suchasthe number of messages an ob ject understands, or the number of arguments needed by a message.

Since much complexity cannot b e avoided, the patterns prefer complexity to b e handled once in server

ob jects, rather than many times in every client ob ject which uses the servers. 1

Pattern Problem Solution

Arguments How can you simplify a complex proto col Make an Arguments Ob ject to capture the

Ob ject

that has a regular argument structure? common parts of the proto col.

Make a single message taking an ob ject

How can you simplify a proto col

Selector

representing the message selector as an ex-

where several messages di er mainly in

Ob ject

tra argument.

their names?

Curried How can you simplify an extremely com-

Send simpler messages to an intermediary

Ob ject plicated proto col?

which elab orates them within its context.

Result How can you manage a dicult answer to Make a Result Ob ject the whole answer to

Ob ject a dicult question? the question.

Future How can you answer a question while you Make a Future Ob ject which computers

Ob ject think ab out something else? the answer in parallel.

How can you answer a question that is

Lazy Make a Lazy Ob ject which can answer the

easy to answer now, but that may never

Ob ject

question later, if necessary.

b e asked?

Figure 1: Summary of the Patterns

Arguments Object Result Object

Selector Object Curried Object Future Object Lazy Object

Figure 2: The Structure of the Language

Several patterns address the cohesion and coupling of the resulting designs, as designs with high

cohesion within ob jects and low coupling b etween them are more exible, understandable, and easier

to maintain. This is often related to whether a concept is represented explicitly by a single ob ject in a

design, or whether it is implicit in the communication b etween several ob jects. Representing a concept

explicitly as an ob ject generally makes it easier to identify the concept within the design, to change the

implementation of the concept if necessary, and to reuse the concept elsewhere, esp ecially if the ob ject

represents a real concept from the program's application domain. The patterns are also concerned with

eciency | the time and space cost of a design, and the number of objects it requires at runtime.

Consequences

A common principle underlies all these patterns | that designs can often b e improved byintro ducing

 nding additional ob jects from within the program. At rst, the newfound ob jects seem out of place

in the program, but as the program evolves, the found ob jects b ecome b etter integrated into the design,

and can b e recognised as mo delling concepts from the application domain.

Because they nd new ob jects, these patterns tend to generate designs with many small, simple

1

ob jects ,intro ducing an extra level of indirection, and imp osing space and time costs at runtime. All

these patterns simplify a design lo cally for example, bychanging one particular proto col but imp ose

global changes to the program b ecause extra ob jects are needed to implement the changed proto col.

As a result, although ob jects may b e easier to understand in isolation, the global design of the program

may b ecome confused. To quote Alan Perlis: In the long run every program becomes rococo | then

rubble. [20]. If these patterns are applied injudiciously they will accelerate this pro cess.

1

This is not limited solely to these patterns. Many other patterns have this e ect, including those in

[9] and Smal ltalk Best Practice Patterns [5], as do Parnas's criteria for program decomp osition [19]. 2

Form

The patterns are written in electric mo di ed Portland form. Each b egins with a question in italics de-

scribing a problem, followed by one paragraph describing the pattern's context, and a second describing

the forces the pattern resolves. A b oldface \Therefore:" intro duces a summary of the solution also

italicised followed by the a description of the solution in detail. Then follows an example of using the

pattern, the patterns consequences b ene ts rst, a b oldface But:, then the liabilities and nally some

known uses and related patterns.

Patterns ab out Proto cols

Ob jects communicate via proto cols | a program's proto cols are the glue that binds its ob jects together.

The following three patterns describ e how ob jects can b e found within proto cols.

1 Arguments Ob ject

How can you simplify a complex protocol that has a regular argument structure?

Some ob jects have large and complex proto cols with a regular internal structure. For example, a

graphical View ob ject will provide proto col for drawing manytyp es of ob jects in many di erentways,

but almost every message will take arguments which sp ecify the colour, stipple, and line thickness to

use when drawing. The same combinations of arguments may o ccur across many proto cols, and as a

result, many arguments may b e passed in parallel through many messages and across many ob jects.

Large proto cols are easy to use b ecause they o er a large amount of b ehaviour to their clients.

Unfortunately, they are often dicult or time consuming to implement, and for client programmers to

learn. Every client of a large proto col dep ends up on the proto col's ne details, such as the names and

arguments required by each message, and these dep endencies make large proto cols dicult to change.

Moreover, large proto cols are more likely to be changed than small proto cols | adding an eleventh

argument to a message with ten arguments is qualitatively quite di erent to adding a second argument

to a unary message. To quote Alan Perlis: If you have a procedure with 10 , you probably

missed some [20].

Therefore: Make an Arguments Ob ject to capture the common parts of the protocol.

In its simplest form, an Arguments Ob ject should have one variable for each argument to be

eliminated from the proto col, and the usual messages to access and up date its variables. Change the

proto col and its implementations to accept a single Arguments Ob ject in place of the eliminated

arguments, and change the proto col's clients to create Arguments Ob jects as required. To supp ort

optional arguments, initialise the Arguments Ob ject's variables with default argumentvalues when

it is created.

Example

Consider the proto col provided by a graphical View ob ject:

drawRectangleFrom: topLeft to: b ottomRight colour: colour

llRectangleFrom: topLeft to: b ottomRight colour: colour

drawOvalFrom: topLeft to: b ottomRight colour: colour

These messages take a number of arguments in common: topLeft, b ottomRight and colour. An

Arguments Ob ject can eliminate these arguments from the proto col. The Arguments Ob ject

whichwe will call a Graphic uses three variables to replace the common arguments. Graphic's proto col

includes messages to create new Graphic ob jects, and to read and write these variables. The View's

proto col can b e changed to accept a single Graphic argument, rather than the three common arguments. 3 client view

drawRectangleFrom:to:colour:

fillRectangleFrom:to:colour:

drawOvalFrom:to:colour:

\Create a Graphic"

g := Graphic from: topLeft To: b ottomRight Colour: colour.

\Draw it"

view drawRectangle: g.

client graphic1 graphic2 graphic3 view

from:To:Colour:

drawRectangle: graphic1

from:To:Colour:

fillRectangle: graphic2

from:To:Colour:

drawOval: graphic3

Consequences

An Arguments Ob ject makes a tradeo b etween the size of a complex proto col M messages with

N common arguments versus M messages with N fewer arguments plus a new Argument Ob ject

which requires N arguments to create it. The resulting proto cols are usually easier to learn and to read.

An Arguments Ob ject decreases the coupling between ob jects involved in the proto col | ob jects

are coupled to the Arguments Ob ject ob ject, rather than to each other | so manychanges to the

proto col are limited to the Arguments Ob ject and those ob jects which fundamentally rely on the

changed proto col. Ideally,anArguments Ob ject will explicitly reveal an ob ject from the application

domain. But: Arguments Ob ject clients may be more dicult to write, as the programmer must

understand b oth the server's proto col and the Arguments Ob jects, and create the necessary Argu-

ments Ob jects as appropriate. As with all these patterns, this pattern intro duces an additional ob ject

into the design, requiring mo di cations to the program and increasing runtime space and time costs.

Known Uses

MacApp uses Event ob jects to package the arguments sent to widgets in resp onse to user actions [24].

The X Window System's drawing op erations use GraphicsContexts to package up a large number of

arguments such as the font, colour, line width, and clip region [22]. 's Point and Rectangle

ob jects can b e seen as Arguments Ob jects which package up two or four integer arguments to describ e

p oints or rectangles [4]. Smalltalk also uses Message ob jects which record the arguments and name of

a message which has caused an error [10]. 4

Related Patterns

The following two patterns describ e how Arguments Ob ject can b e applied in particular situations.

The numb er of message names in a proto col can b e reduced by using a Selector Ob ject 2. Constant

or slowly-varying arguments can be factored out by a Curried Ob ject 3, which intro duces an

intermediary ob ject to elab orate a proto col.

2 Selector Ob ject

How can you simplify a protocol where several messages di er mainly in their names?

Some proto cols include several messages which p erform the same underlying . For example,

a graphical View ob ject provides many messages which draw graphical ob jects. These messages take

substantially the same arguments and di er in the ne details of the precise function they p erform |

in the case of the View, whether to draw a rectangle, a lled rectangle, or an oval.

Proto cols where many messages p erform similar functions are often dicult to learn and to use,

esp ecially as the similarity is often not obvious from the proto col's do cumentation. Because the messages

are conceptually closely related, they will often need to b e maintained as a group, which will require

changing a numb er of metho implementations in servers and many di erent message sends in clients.

Therefore: Make a single message taking an object representing the message selector as an extra

argument.

Remove the similar messages from the proto col, and replace then with a single message which takes

the Selector Ob ject as an additional argument. This message should p erform the essential function

p erformed by the messages from the original proto col, and use the Selector Ob ject argument to

discriminate b etween the functions in detail typically using multimetho ds or double dispatching [9].

Change the proto col's clients and servers to use the new proto col.

In some cases, the Selector Ob ject can be a very lightweight ob ject, such as a symbol or enu-

meration, which is used only to determine the ne details of the function to be p erformed. In other

cases, the Selector Ob ject can have substantial state and b ehaviour of its own. If you already have

an Arguments Ob ject, the Selector Ob ject can b e often b e folded into it, resulting in a Message

Ob ject.

Example

Consider the proto col provided by a graphical View ob ject, which uses a Graphic Arguments Ob ject

as describ ed ab ove.

drawRectangle: aGraphic

llRectangle: aGraphic

drawOval: aGraphic

Each of these three messages p erforms essentially the same function | drawing on a View. The

details of the function whether to draw a rectangle outline, a lled rectangle, or an oval are enco ded

in the message selector. In this example, we have an Arguments Ob ject the Graphic, so we can

the Selector Ob ject pattern to incorp orate the message selector into the Arguments Ob ject.

Graphic can b e extended to record a typ e, which selects either outlined rectangles, lled rectangles, or

ovals to b e drawn. View's proto col now contains only a single message, draw, mo delling the one essential

function of the whole proto col.

\Create a Graphic"

g := Graphic

typ e: rectangle from: topLeft

to: b ottomRight colour: colour.

\Draw it"

view draw: g. 5

As an alternative, a family of Graphic sub class can b e used, rather than the typ e argument.

graphic := RectangleGraphic

from: 10@10 to: 20@20 colour: red.

view draw: graphic.

client rectangle filledRectangle oval view

from:To:Colour:

draw: rectangle

from:To:Colour:

draw: filledRectangle

from:To:Colour:

draw: oval

Consequences

The Selector Ob ject pattern is a re nementofArguments Ob ject 1, and its b ene ts and liabilities

are similar. The tradeo is slightly di erent|Selector Ob ject trades o N similar messages at the

server for 1 message with an extra argument plus the Selector Ob ject and its creation message. When

this factorisation results in Selector Ob jects which have meaning in the domain, the proto col will

be smaller and easier to mo dify, and also easier to learn and to use. But: clients need to create the

Selector Ob ject, and servers need some mechanism to select the actual function the message will

p erform.

Known Uses

Selector Ob jects are often used to build ob ject oriented interfaces to existing le or graphics systems.

For example, VisualWorks uses symb ols representing le access mo des as arguments to messages to

manage les [18]. Many OO graphics systems, again including VisualWorks, provide Geometric or

Graphic ob jects which combine the Selector Ob ject and Arguments Ob ject 1 patterns.

Related Patterns

Lightweight Selector Ob jects can often b e Flyweights [9].

3 Curried Ob ject

How can you simplify an extremely complicatedprotocol?

Over the course of a program, ob jects exchange messages, and the ob jects passed as arguments to

these messages are usually di erentevery time. Sometimes, an ob ject will receive a series of messages

where one or more arguments are constant. For example, a text editor will often draw a number of

di erent strings in exactly the same font size, typ eface, and colour. Arguments may also be sent in

sequence, so that the argument to one message can b e predicted from the corresp onding argumentofa

previous message | the text editor will draw the strings with the same left margin, but each o one

line lower on the screen.

These kinds of arguments increase the complexity of a proto col. The proto col will be dicult to

learn, as programmers must work out which arguments must be changed, and which must remain 6

constant. This information is not explicitly represented in the proto col, and often not provided by

standard do cumentation. The proto col will b e dicult to use, as clients must cache constant arguments

between sends and compute the values of slowly-varying arguments.

Therefore: Send simpler messages to an intermediary a Curried Ob ject which elaborates them

within its context.

A Curried Ob ject stores the constantorslowly varying arguments from the original proto col, and

provides a simpler proto col with these arguments eliminated. A Curried Ob ject stores the original

server ob ject, and forwards messages to this ob ject, passing along the stored arguments and up dating

the slowly varying arguments.

To use a Curried Ob ject,change clients so that rather than sending messages to the server, they

create a curried ob ject, initialise it as required, and send messages to it. Proto col can b e added to the

server for creating and initialising a Curried Ob ject which refers to that server. The original proto col

can remain publicly available in the server, or it can b e restricted to the Curried Ob ject.

Example

Consider drawing lines of text on a graphical view:

font := Font named: Times .

o set := 0 @ font textHeight.

view drawString: This is an example at: origin font: font.

view drawString: to illustrate at: origin + o set font: font.

view drawString: the problem at: origin + o set  2 font: font.

client view

drawString:at:font:

drawString:at:font:

drawString:at:font:

The drawString:At:Font message takes three arguments. The rst argument, the string to draw, is

di erent for each message sent; the second argument, the p oint at which to draw the string, varies

according to an arithmetic progression; and the third argument, the font to use, is constant.

This proto col can b e simpli ed byintro ducing a Curried Ob ject. The Curried Ob ject whichwe

will call a Pen requires three variables to hold the View server ob ject, and the origin and font arguments

of the drawString:At:Font message. Pen's proto col will include messages to read and write these variables,

and a single argument message drawString to draw a string and advance to the next line up dating the

origin variable. The View ob ject needs a single argument message pen which returns a new Pen ob ject

asso ciated with the View. Using a Pen, the example ab ove b ecomes:

p en := view p en at: origin font: font named: Times .

p en drawString: This is an example .

p en drawString: to illustrate .

p en drawString: curried objects . 7 client pen view

pen new

at:font:

drawString: drawString:at:font:

drawString: drawString:at:font:

drawString:

drawString:at:font:

Consequences

Curried Ob ject is quite similar to Arguments Ob ject 1, and shares most of the b ene ts and

liabilities of that pattern, however, it requires fewer changes to existing servers. But: Curried Ob ject

displaces the receiver of the proto col, while Arguments Ob ject 1 do es not. Curried Ob ject thus

intro duces action at a distance, b ecause messages sent to one ob ject the Curried Ob ject are actually

executed by another the original server ob ject. A Curried Ob ject is at the same level of abstraction

as its server, and acts as an alias for the server. Programmers need to know ab out b oth the original

server and the Curried Ob ject, and understand the distinctions b etween them, in particular, which

messages to send to which ob ject.

This pattern is called Curried Object b ecause the underlying mechanism is partial function applica-

tion, collo quially known as after the mathematician Haskell B. Curry [12]. The name Curried

Object also suggests that this pattern is a little spicy and exotic, and probably not for the b eginner.

Known Uses

Iterators are the most common of Curried Ob ject, as they are used in many common languages

and class libraries [9, 10, 6]. An iterator's server is a collection ob ject, and the iterator maintains a

slowly varying index into the collection. Many graphics systems use Curried Ob jects whose servers

are views, as in the example ab ove. For example, VisualWorks uses GraphicsContext ob jects [18] and

Smalltalk/V uses Pen ob jects [15]. VisualWorks also includes MessageSend ob jects, a curried version of

the Message Arguments Ob ject 1. MessageSend inherits from Message, and adds an extra variable

to store the message's receiver, allowing a message to sent without an explicit reference to the ultimate

receiver ob ject.

Related Patterns

Arguments Ob ject 1 can provide a less radical alternative to Curried Ob ject. The original

server can act as an Abstract Factory [9] to create the Curried Ob ject. A Curried Ob ject can b e

similar to an ob ject-level Adaptor [9], but where an adaptor allows an ob ject to conform to an existing

proto col, a Curried Ob ject intro duces a new, simpler proto col. The Accumulator [25] pattern is

a variant of Curried Ob ject which simpli es the proto col used to create ob jects. The Typ e-Safe

Session pattern is a Curried Ob ject which emphasises typ e safety [21].

Patterns ab out Results

Many messages ask questions of the ob jects to which they are sent, and the results of these messages

are the answers to these questions. The following three patterns describ e how ob jects can simplify the

asking and answering of questions. 8

4 Result Ob ject

How can you store and manage a dicult answer to a dicult question?

You have a long or imp ortant computation p erformed by a server ob ject, and you wish to retain

the results of the computation. Perhaps the computation returns more than one ob ject, or the result

is needed at several times or places throughout the program, or you need to keep information ab out

how the result was obtained. For example, consider a MetricCalculator for a programming environment

that calculates software metrics for a system under development. Calculating the metrics is a long

computation and needs to return values for a numb er of di erent metrics. The programming environment

needs to keep the values for the di erent metrics together, and to store the values to track the evolution

of the system over time.

The client ob ject could cache the results itself, but this increases the client's complexity, as the

resulting caching co de will obscure the main application logic, making it dicult to read and mo dify.

Alternatively, the server ob ject could cache and store the results, but this has similar problems, in that

the caching co de p ollutes the implementation of the domain computation. This also complicates the

server's proto col, since it must return b oth previous and current results.

Therefore: Make a Result Ob ject the whole answer to the question.

Make one variable in the Result Ob ject for eachvalue to b e returned, and provide the usual accessor

and initialisation messages | if additional information ab out the result is required, store this in the

Result Ob ject also. Provide the usual accessor messages so that this information can be retrieved

from the Result Ob ject. Mo dify the server to create and return a Result Ob ject, and the server's

clients to retrieve the results from the Result Ob ject.

Example

Consider a MetricCalculator ob ject for calculating software metrics:

m := MetricCalculatorfor: anObject.

m computeSizeOfInterface.

m computeNumb erOfInheritedMetho ds. m computeNumb erOfOverriddenMetho ds.

Client MetricCalculator

computeSizeOfInterface

computeNumberOfInheritedMethods

computeNumberOfOverriddenMethods

The various compute messages traverse the target ob ject's inheritance hierarchy and compute metrics.

The hierarchy is traversed whenever an individual metric is required, and rep eated if the metric is needed

again. Since each metric requires exactly the same traversal of the inheritance hierarchy, this is really

a single computation returning multiple results | the various di erent metrics.

This proto col can b e improved byintro ducing a Result Ob ject. All the metrics can b e calculated

in one traversal, and a Result Ob ject called a MetricRep ort returned. Individual metric values can

b e retrieved from the MetricRep ort. The MetricRep ort ob ject can also store ancillary information ab out 9

the metric calculation, such as the date the metrics were calculated. Using a MetricRep ort, the ab ove

example b ecomes:

metricRep ort := MetricCalculatorfor: anObject computeMetrics.

metricRep ort sizeOfInterface.

metricRep ort numb erOfInheritedMetho ds.

metricRep ort numb erOfOverriddenMetho ds.

Client MetricReport MetricCalculator

computeMetrics new

sizeOfInterface

numberOfInheritedMethods

numberOfOverriddenMethods

Consequences

A Result Ob ject is quite likea Curried Ob ject 3 and shares many of the b ene ts and liabilities of

that pattern, except that a Curried Ob ject 3 substitutes for a message's receiver, while a Result

Ob ject substitutes for a message's result. A Result Ob ject trades the server's proto col size for extra

ob jects | M messages to the server are replaced by 1 message to return a Result Ob ject plus M

messages to retrieve the result values | the resulting proto cols are usually easier to learn and to read,

and with reduced coupling, are easier to change. Result Ob ject is particularly p owerful when the new

Result Ob ject corresp onds to a concept from the domain. But: for the client ob ject programmer,

Result Ob jects are more dicult to use than server-side caching, b ecause the client needs to extract

the actual results from the Result Ob ject. For the server ob ject programmer, they similarly require

more work than client-side caching.

Known Uses

The VisualWorks Date class returns a Result Ob ject called TimeStamp to package together the

current date and time. As well as simplifying client co de, this also avoids the problems whichwould

o ccur if the time was returned at one second b efore midnight, and the date one second afterwards. Martin

Fowler discusses similar Result Ob jects called TimePoints [8]. An exp ert system used in Telecoms

capacity planning used a Result Ob ject to package the decisions it returned with the logic supp orting

the decisions. The system's users could check the supp orting logic to verify that the decisions were

b eing made appropriately. The Self Programmer's Reference Manual describ es how Result Ob jects

can b e used in Self to return multiple values from messages [1].

Result Ob jects are often used to provide error handling resulting in Error Ob jects. Represent-

ing errors with Result Ob jects allows the errors to b e queued as they o ccur, and displayed later to the

user. These Result Ob jects can also provide textual descriptions of the errors, and appropriate help

information. For example, VisualWorks includes SystemError ob jects, Result Ob jects which package

together return co des and identifying arguments from errors o ccurring outside the system [18]. 10

Related Patterns

If the question can b e answered in parallel, try Future Ob ject 5. If the question can b e answered

easily now, but the answer may never b e needed, try Lazy Ob ject 6.

5 Future Ob ject

How can you answer a question while you think about something else?

Sometimes you need to ask a question, then do something else while waiting for the answer to

arrive. For example, a programming environment may need to resp ond to its user interface while a

MetricCalculator computes the metrics for the latest release. In these cases, the computation's result

must b e returned to the program eventually, but it is not needed immediately. If the computation can

b e p erformed indep endently from the rest of the program | that is, if the computation do es not mo dify

ob jects which the rest of the program dep ends up on, and vice versa | it should b e p ossible to compute

the result in a parallel .

Unfortunately, managing parallel threads is quite dicult in practice. Because the computation's

result is eventually required by the program, the thread cannot be started in parallel and left to its

own devices. Rather, the result must be returned to the program when the computation nishes. If

the server starts the parallel computation, then either the server or the computation's clients must

extract the result from the thread. This will increase the complexity of the ob ject chosen to have this

resp onsibility, and reduces cohesion by contaminating it with pro cess management issues. In practice,

programmers often adopt the simplest solution, ignoring the issue and computing the result immedi-

ately, delaying the program's execution until the computation is complete, consequently reducing the

program's resp onsiveness and p erformance.

Therefore: Make a Future Ob ject which computes the answer in paral lel.

A Future Ob ject is a Result Ob ject 4 which computes an answer in a parallel thread, based

on initial information supplied by the original server [11]. The Future Ob ject should receive the

computation's arguments from the server, and then cache any information whichmaychange after the

main computation resumes. The Future Ob ject should handle the thread management | creating a

new thread to p erform the computation, and extracting the results when the thread completes. The

Future Ob ject should also provide synchronisation | clients which access the Future Ob ject while

its asso ciated thread is running should b e blo cked until the thread completes.

The Future Ob ject can also be used to control the thread p erforming the computation. This

control can b e direct | the Future Ob ject can provide an interface to control the thread, or indirect

|ifthe Future Ob ject is deleted b efore its computation completes, the unneeded computation can

also b e deleted.

Example

Consider the metricRep ort example from the Result Ob ject 4 pattern. A Future Ob ject could

implement the metricRep ort with exactly the same interface, but with a di erent p erformance pro le.

Using a Result Ob ject, the program will wait while the computation is p erformed. Using a Future

Ob ject, the computation will b e p erformed in a parallel thread started by the computeMetrics message,

and the program will wait for this thread when it accesses the metricRep ort Future Ob ject | in the

diagram, when the sizeOfInterface message is sent. If the creation of the Future Ob ject and its rst

access are suciently separated, the metrics computation will not delay the main thread.

Consequences

A Future Ob ject proto col is exactly the same as a Result Ob ject 4, and so has similar b ene ts

of increased readability and decoupling, and decreased complexity. In addition, a Future Ob ject sep-

arates concurrency issues from clients' and servers' domain co de, so the implementation of concurrency

is easier to change. But: b ecause a Future Ob ject must manage the concurrency, it will have a larger

overhead than a standard Result Ob ject. A Future Ob ject will also b e more dicult to write than a 11 Client MetricReport MetricCalculator

computeMetrics new

sizeOfInterface

numberOfInheritedMethods

numberOfOverriddenMethods

Result Ob ject, although some languages are suciently exible that a single generic Future Ob ject

can b e written once and reused as necessary [7]. A Future Ob ject cannot avoid the intrinsic problems

imp osed by concurrency: the program's p erformance will b ecome less predictable, and harder to debug

[16]. Also, this pattern should b e applied only when the parallel computation is indep endent of the rest

of the program.

Known Uses

Future Ob jects are quite common in parallel and . They were intro duced in

Multilisp [11] and have b een used in Smalltalk [7] and Mushroom [13] amongst many other systems

[16].

Related Patterns

Future Ob ject has b een describ ed brie y as part of the Active Ob ject pattern [23]. A Future

Ob ject can b e seen as a Proxy [9] for an ob ject which hasn't b een computed yet.

6 Lazy Ob ject

How can you answer a question that is easy to answer now, but that may never be asked?

Some computations can b est b e p erformed immediately but the computation's result may never b e

needed. For example, the data needed by the MetricCalculator may only b e accessible for the current

version of the software b eing develop ed, but it is unlikely that the user would want metrics calculated for

every intermediate version. Often this kind of computation dep ends on information whichisavailable

now, but may not b e available in the future.

The simplest solution to this problem is for the client to ask the question every time, and then store

the results until they are needed. If most of the results are not needed, this will cause a large amountof

unneeded computation, and also complicate the client's co de, making it harder to write. Alternatively,

the server ob ject answering the question could compute and cache all the results, with a similar problems

of eciency and increased server complexity. The client could p ostp one asking the question until the

answer is required, but, when the question is asked, the information the answer dep ends up on maybe

lost.

Therefore: Make a Lazy Ob ject which can answer the question later, if necessary.

A Lazy Ob ject is a Result Ob ject 4 which do es not start its computation until the answer is

requested. The laziness is managed within the Lazy Ob ject, rather than by the clients or server. A

server ob ject can initialise and return a Lazy Ob ject in exactly the same wayitwould return a Result

Ob ject. The server should pass the computation's arguments to the Lazy Ob ject, which should also

cache any information whichmaychange b etween the time it is created and the time it is used. When 12

it is accessed, the Lazy Ob ject cannot return the result of the computation, b ecause the computation

has not yet b een carried out. Rather, the rst time the Lazy Ob ject is used, it should p erform the

computation and cache the results. Future requests can b e serviced from the cache.

Example

Consider again the metrics calculator example from Result Ob ject 4. A Lazy Ob ject could be

used as the metricRep ort,changing the p erformance characteristics but not the interface. Using a Lazy

Ob ject, the metrics computation will b e p erformed when the rst metric is requested | in the example,

when the sizeOfInterface message is sent. If the result is never needed, the Lazy Ob ject can b e deleted

or garbage collected, and the metrics will never b e calculated.

Client MetricReport MetricCalculator

computeMetrics new

sizeOfInterface

numberOfInheritedMethods

numberOfOverriddenMethods

Consequences

A Lazy Ob ject is a re nement of a Result Ob ject, and shares the b ene ts and liabilities of that

pattern. In addition, a Lazy Ob ject avoids the overhead of unnecessary computations by calculating

only results that are actually required. Since a Lazy Ob ject's own proto col is exactly the same as that

of a corresp onding Result Ob ject, the choice to use or not use can b e completely

encapsulated from any client ob jects. Similarly, b ecause the Lazy Ob ject manages the evaluation

itself, the server is mostly insulated from the details of the laziness. But: these gains in eciency

must b e traded o against the need to identify and cache information which the computation dep ends

up on and which mightbechanged by the rest of the program, and to ensure the computation when

eventually p erformed do es not itself have side e ects on the rest of the program. A Lazy Ob ject may

make program p erformance dicult to predict, and the program dicult to debug, b ecause it is not

easy to determine when or if  the calculation is actually carried out.

The Result Ob ject 4, Future Ob ject 5, and Lazy Ob ject 6 patterns are distinguished

by when the computation is started, and when the result is returned to the main thread. A Result

Ob ject starts the computation and returns the result as so on as it is created, a Future Ob ject starts

a computation as so on as it is created, but returns the result when it is rst accessed, and a Lazy

Ob ject b oth starts the computation and returns the result when it is rst accessed.

Known Uses

The mushroom system implements a generic Lazy Ob ject [13]. The LOOM virtual memory system for

Smalltalk used Lazy Ob jects called leaves to represent ob jects whichwere swapp ed out into secondary

storage [14]. Design Patterns describ es how ET++ uses Lazy Ob jects called virtual proxies to represent

large images whichmay not need to b e displayed [9].

Related Patterns

Ken Auer and Kent Beckhave describ ed many similar patterns for optimising Smalltalk programs [2]. 13

Acknowledgements

These patterns are revised versions of some patterns from the Found Objects pattern language [17 ], and were

inspired by discussions on the patterns-discussion mailing list and the WikiWikiWeb. In particular,

describ ed Parameters Object [4 ] and suggested Result Object [3 ]. Patrick Logan noticed the similaritybetween

these two patterns, David C. Laurence provided the Telecoms example for Result Ob ject and Mike Koss

describ ed the use of Result Ob jects to handle errors.

Authors and reviewers at the EuroPLOP'96 and PLOP'97 writers workshop provided many p ertinent com-

ments and suggestions. Lorraine Bo dy, , and Charles Weir provided detailed comments on the

conference draft, as did David Holmes back at MRI and a numb er of anonymous reviewers. Shepherds Ward

Cunningham and Paul Dyson provided many imp ortant suggestions regarding the pap er's form and content.

References

[1] Ole Agesen, Lars Bak, Craig Chamb ers, Bay-Wei Chang, Urs Holzle, John Maloney, Randall B. Smith,

David Ungar, and Mario Wolczko. The Self Programmer's Reference Manual. Sun Microsystems and

Stanford University, 4.0 edition, 1995.

[2] Ken Auer and Kent Beck. Lazy optimization: Patterns for ecient smalltalk programming. In Pattern

Languages of Program Design,volume 2. Addison-Wesley, 1996.

[3] Kent Beck. Result ob ject. http://c2.com/cgi/wiki?ResultO bject .

[4] Kent Beck. Parameters ob ject. Email message sent to the patterns-digest list, March 1995.

[5] Kent Beck. Smal ltalk Best Practice Patterns. Prentice-Hall, 1996.

[6] Grady Bo o ch. Object OrientedAnalysis and Design with Applications. Benjamin Cummings, second edition,

1994.

[7] Brian Fo ote and Ralph E. Johnston. Re ective facilities in Smalltalk-80. In OOPSLA Proceedings, 1989.

[8] Martin Fowler. Analysis Patterns. Addison-Wesley, 1997.

[9] Erich Gamma, Richard Helm, Ralph E. Johnson, and John Vlissides. Design Patterns. Addison-Wesley,

1994.

[10] Adele Goldb erg and David Robson. Smal ltalk-80: The Language and its Implementation. Addison-Wesley,

1983.

[11] Rob ert H. Halstead, Jr. Multilisp: A language for concurrent symb olic computation. ACM Transactions

on Programming Languages and Systems, 74:501{538, Octob er 1985.

[12] Martin C. Henson. Elements of Languages. Blackwell Scienti c, 1987.

[13] Trevor P. Hopkins and Mario Wolczko. Writing concurrent ob ject-oriented programs using Smalltalk-80.

The Computer Journal, 324, Octob er 1989.

[14] Ted Kaehler and Glenn Krasner. LOOM{large ob ject-oriented memory for Smalltalk-80 systems. In Glenn

Krasner, editor, Smal ltalk-80: Bits of History, Words of Advice,chapter 14. aw, 1983.

[15] Wilf Lalonde. Discovering Smal ltalk. Benjamin/Cummings, 1994.

[16] Doug Lea. Concurrent Programming in Java. Addison-Wesley, 1997.

[17] James Noble. Found ob jects, 1996. Reviewed at EuroPLOP.

[18] ParcPlace Systems. VisualWorks Smal ltalk User's Guide, 2.0 edition, 1994.

[19] David Lorge Parnas, Paul C. Clements, and David M. Weiss. The mo dular structure of complex systems.

IEEE Transactions on , 113, March 1985.

[20] Alan Perlis. Epigrams on programming. ACM SIGPLAN Notices, 179, Septemb er 1982.

[21] Nat Pryce. Typ e-safe session. In EuroPLOP'97 Proceedings, 1997.

[22] Rob ert W. Schei er and Jim Gettys. The X Window System. ACM Transactions on Graphics, 52, April

1986.

[23] Douglas C. Schmidt and Charles D. Cranor. Active ob ject: An ob ject b ehavioral pattern for concurrent

programming. In Pattern Languages of Program Design,volume 2. Addison-Wesley, 1997.

[24] Kurt Schmucker. MacApp: an application framework. Byte, 118, 1986.

[25] Phillip M. Yelland. Creating host compliance in a p ortable framework: A study in the use of existing design

patterns. In OOPSLA Proceedings, 1996.

[26] Walter Zimmer. Relationships b etween design patterns. In Pattern Languages of Program Design. Addison-

Wesley, 1994. 14