<table><tr><td>rounded</td><td>round to nearest</td><td>truncate</td><td>round down</td></tr></table>

In general, the arithmetic operators available in Smalltalk are essentially the same as in any other language. For example, there is addition, subtraction, multiplication and division operators (+, -, *./). There are also comparison functions and truncation functions all of which are summarized in Table 7.1.

## 7.3 Characters and strings

### 7.3.1 Characters

Just like numbers, characters in Smalltalk are instances of an associated class. In this case the class `Character`. Again we will consider this class and the operations it provides in greater detail later. For the moment we will consider what characters look like. In Smalltalk, a single character is defined by prefixing it with the `$` (dollar) sign. For example:

`$a $Z $@ $1 $$`

All the above specify a single character, in this case the characters `a`, `b`, `@`, `1` and `$.`

### 7.3.2 Strings

Strings in Smalltalk are part of the `Collection` class hierarchy. As such they are made up of individual elements in a similar manner to strings in C. However, this is the only similarity between C strings and Smalltalk strings. Smalltalk strings do not need to be terminated by a null character, nor should they be treated as arrays of characters. In Smalltalk, a string should be treated as an object in its own right which responds to an appropriate range of messages (e. g. for manipulating or extracting substrings).

In Smalltalk, a string is defined by one or more characters placed between single quotes. For example:

`'John Hunt' 'Tuesday' 'dog'`

Note the use of single quotes rather than the double quotes used in some other languages (e.g. C and Ada). This can be the source of much confusion and frustration when an apparently correct piece of code will not work. Remember that double quotes indicate a comment in Smalltalk. Thus, the following code will compile, but will generate a run time error:

`a := "John Hunt".`

This is because there is nothing to assign to the variable `a` as the comment "John Hunt" does not return a value. Also be wary of assuming that a string containing a single character is equivalent to that single character. It is not. For example:

`'a' /= $a`

The string 'a' and the character `$a` are instances of different classes, the fact that the string contains only one character is just a coincidence. This can be particularly confusing for C programs as 'a' indicates the character `a` in C.

### 7.3.3 Symbols

Symbols are special strings which are always unique in the system. They do not respond to many of the usual string manipulation messages, but they can be more efficient for some tasks than strings. A symbol is indicated by a preceding hash (`#`). For example:

`#john #Week #System42`
They are more efficient for storage and certain logical operations (such as `=`) and so may be used instead of strings if their values will not be altered and substring operations are not required.

## 7.4 Assignments

A variable name can refer to different objects at different times; assignments can be made to variable names. The `:=` symbol is used in Smalltalk to indicate assignment. It is often read as "become equal to" although some do read it as "colon equals". Some examples are:

```
currentEmployeeIndex := 1.
newIndex := oldIndex.
myName := 'John Hunt'.
```

Assignments return values (like other expressions), so that several assignments can be made together:

```
nextObject := newObject := oldObject.
```

The above example also illustrates a feature of Smalltalk style - the specification of variable names which indicate what they contain. This technique is often used where a more meaningful name (such as `currentEmployeeIndex`) is not available, i.e. where `temp` might be used in other languages.

It is worth reiterating the point that variables in Smalltalk are not strongly typed as in languages such as Pascal and ADA. Instead, Smalltalk is dynamically typed. That is, a variable is not un-typed, rather its type is determined by its current contents. Thus, it is possible to determine the type contained in a variable by sending it a message asking for its type. Of course, by type we really mean class. It is also possible that a variable which is currently holding a string, may then be assigned an integer. This is quite legitimate and often happens, for example:

```
myVariable := 'John'.
myVariable := 1.
myVariable := # (1 2 3 4).
```

An important point to note is that assignment is by reference. This means that in the following example `nextIndex`, `newIndex` and `oldIndex` all refer to the same object.

```
new := old := (Bag new).
next := new.
```

The effect of these assignments is illustrated in Figure 7.1.

<figure><img src="image_39.png" /><figcaption>Figure 7.1: The result of a multiple assignment</figcaption></figure>

As all three variables point to an instance of a container class (in this case `Bag`), if an update was made to the contents of any one of the variables, it would be made for all three!

## 7.5 Variables

### 7.5.1 Types of variable

There are a number of different types of variable available in the Smalltalk language. Some of these have already been discussed. The following provides a review of some of the different types:
1. instance variables - discussed above

2. class variables - will be discussed later in the book

3. class instance variables - will also be discussed later in the book

4. temporary variables - see below

5. global variables- see below

### 7.5.1.1 Temporary variables

These exist only for the duration of some activity (e.g. the execution of a method). They are denoted by being placed between two bars, e.g. `| x y z |` indicates that the variables x, y and z are temporary variables. Try typing the following into the Workspace window:

```
| x y z |
x := 5.
y := 6.
z := x + y.
Transcript show: z printString.
```

Now select all the text you typed in. Now use the right mouse button (middle if you have a three button mouse) and select the **do it** option on the menu. You should now see the value 11 printed in your Transcript window.

### 7.5.1.2 Global variables

These are shared by all instances of all classes. These can be useful during testing if you want to keep hold of a particular object. They always start with a capital letter and can be deleted by looking at the Smalltalk system dictionary. This can be accessed from the global variable Smalltalk (you can use the inspect message to examine the contents of the variable Smalltalk). To delete a global variable from the current system, use:

```
Smalltalk removeKey: #<global variable name>.
```

It is interesting to note that class names start with a capital letter and are therefore actually global variables!

## 7.5.2 Pseudo variables

There are a number of pseudo variables in Smalltalk which can be referenced within a method. A pseudo variable is a special variable, whose value is changed by the system but which cannot be changed by the programmer. That is, the value of these variables is determined by the current context within which the code around it is executing. There are two such pseudo variables; they are `self` and `super`:

**self** This refers to the receiver of a message itself. When a message is received, the search for the corresponding method starts in the class of the receiver. It is the way in which a method in one object can initiate the execution of another method in that same object.

**super** Also refers to the message receiver, but the method search starts in the superclass of the class in which `super` is used. This is often used if the functionality of a method is to be extended rather than overwritten. For example:

```
myMethod: anObject
new code before super.
super myMethod.
new code after super.
```

Don't worry about the syntax or the meaning of this at the moment just make sure you get the idea of things.
### 7.5.3 true, false and nil variables

These variables represent the two boolean states, true and false and a null value (referred to as `nil`). This should not be confused with the null pointer in languages such as C. It really means *nothing* or *no value*. The three variables are:

* `nil` The single instance of class *Undefined Object* (the non-value).

* `true` Represents truth. It is the only instance of class *True*.

* `false` represents falsehood. Which is the only instance of the class *False*.

`True` and `False` are subclasses of `Boolean` which implements boolean algebra and control structures.

## 7.6 Messages and message selectors

### 7.6.1 Message expressions

*Message expressions* describe messages to receivers. They are composed of a receiving object (the receiver), the message selector (which indicates which method to execute) and zero or more parameters. Figure 7.2 illustrates the main components of a message expression.

<figure><img src="image_40.png" /><figcaption>Figure 7.2: The components of a message expression</figcaption></figure>

The value of the expression is determined by the method it invokes. For example, in the following example, the result returned by the method `marries:` is saved into the variable `newStatus`.

```
newStatus := thisPerson marries: thatPerson.
```

### 7.6.2 Message types

There are three different forms which a message can take. From the programmers point of view they are essentially the same. They are only distinguished by the format they take and by the precedence they have. The following description explains each of the three types of message and states their precedence. The only exception to this is that parenthesized expressions take precedence over all message expressions.

Messages without any arguments are termed *Unary Messages*, for example:

```
#($a $b 23 'john') size.
13 odd.
Time now.
```

Messages with a single argument, where the selector is composed of one or two non-alphanumeric symbols are termed *Binary Messages*. They have a higher precedence than keyword messages, but a lower precedence than unary messages. Examples of binary messages include:

```
a >= b. 24 * 7.      recordCount + 1.
```

The second character in a binary message selector *cannot* be a minus sign.
Messages with one or more arguments, separated by part of the method selector and composed of alphanumeric symbols and a trailing colon, are called *Keyword Messages*. For example:

```
Transcript show: 'Hello John'.
10 max: 20.
aDictionary at: 'UK' put: 'United Kingdom'.
```

In the above examples `show:`, `max:` and `at:put:` are the keywords (termed selectors). This means that the name of a message selector is spread amongst the arguments. These can be any simple identifier with a trailing colon. The argument can be an expression representing any object. Keyword expressions have the lowest precedence.

### 7.6.3 Message selectors

A message selector is the term used to describe the method interface provided by one object to other objects. For example, if an object possesses a method with the following definition then it possesses a message selector of `"addAddress:for:"`.

```
addAddress: anAddress for: aName
addressBook at: aName put: anAddress.
```

Notice that the method selector only consists of the method name and does not include any of the parameters dispersed amongst that name.

### 7.6.4 Precedence

Smalltalk has slightly different rules regarding precedence than many other languages. For those of you who are unclear about precedence, this refers to the order in which operators are evaluated in an expression. Many languages, such as C, have quite complex rule s regarding precedence, which determine the order in which an expression such as:

$$2 + 5 * 3 - 1 / 2.$$

would be evaluated. Smalltalk is rather more intuitive. Essentially it handles parsing in a left to right manner. For example, in the above example, 5 is added to 2, the result (7) is multiplied by 3 (to give 21). 1 is subtracted from this (giving 20) which is divided by 2. The result of this expression is therefore 10. That is, there is no precedence difference between `+`, `-`, `*` or `/`. If you wish to alter t he way in which the arithmetic calculations are performed, then you can use round brackets. For example:

$$2 + (5 * 3) - 1 / 2.$$

This expression will be evaluated to the value 8. This rule also includes unary messages. For example:

```
arraySize := #('a' 'b' 'c' 'd') size even
```

the message `size` is sent to the array object, and `even` is sent to the resulting object. The result of this is then assigned to the variable `arraySize`.

Keyword messages are a special case, in that although they too are parsed in a left to right manner, the system assumes that all the keywords within one expression are part of the same message selector. Thus an expression such as:

```
aDog name: 'Fido' age: 2.
```

will be parsed as calling a message `name:age:`. If this is not the intention then t he programmer must indicate to the system that what is required is that the message `name:` and then a separate message `age:` should be sent to `aDog`. For example, either as separate messages to `aDog` or using the cascading mechanism. A potential point of confusion here is when the intention is to send the second method to the result obtained from the first. For example:
anArray at: 1 max: 10.

This will try and send the message `at:max:` to `anArray`. Here it is necessary to use round brackets to ensure that it is the object returned as a result of accessing position 1 in the array which receives the `max:` message. For example:

(anArray at: 1) max: 10.

### 7.6.5 Parsing rules

Although the order in which expressions are evaluated is left to right, there are three levels of precedence amongst the categories of message which affect this evaluation. The three categories each have a different precedence as indicated by the following table:

<table><thead><tr><td>Message category</td><td>Precedence</td><td>Example</td></tr></thead><tbody><tr><td>unary</td><td>1</td><td>size, rem, odd</td></tr><tr><td>binary</td><td>2</td><td>*, /, -, +</td></tr><tr><td>keyword</td><td>3</td><td>max:, min:, at:put:</td></tr></tbody></table>

This means that a unary message will be evaluated before a binary or keyword message. In turn a binary message will be evaluated before a keyword message. If this order is not what is desired then round brackets can be used to alter the evaluation sequences as above. For example:

2 * 3 max: 3 * 4 odd.

This would generate an error, because, the `odd` message at the end of the expression has the highest precedence. This means that the result of sending the message `odd` to the value 4 would be used as the parameter for the message '*' to be sent to the value 3. As this would result is multiplying 3 by false, the system would generate a run time error. To ensure that we obtain the correct result, we might place brackets around parts of the expression, thus:

((2 * 3) max: (3 * 4)) odd.

This can be a common source of errors. If you have a problem with any of the parsing rules a quick and easy way to make sure the system parses an expression in the way that you want, is to put brackets around parts of the expression to describe your requirements. Then select the **format** menu option in one of the VisualWorks browsers. This option not only formats the code according to Smalltalk standards, it also removes any unnecessary brackets.

## 7.7 Summary

In this chapter you have learnt about classes in Smalltalk, how they are defined, how instance variables are specified and how methods are constructed. You have also encountered many of the basic Smalltalk language structures.

## 7.8 Further reading

Two good books to have a look at now, if you have not already done so, are [Lewis 1995] and [Hopkins and Horan 1995].
# 8. An Example Smalltalk Class

## 8.1 Introduction

You should now be ready to write some Smalltalk code. So this chapter will take you through a worked example. It is a very simple example, in which you will create a new class, define some instance variables and write a couple of methods.

## 8.2 The class Person

The Person class will provide a very basic set of features. It will record a person's name and their age. It will also allow a person to have a birthday (and thus increment their age).

### 8.2.1 Creating the class

The first thing you should do is to create a new class category to put your class into. This is done in the class category window of the System Browser. Use the right button menu (middle on a three button mouse) and select the add option. This option will prompt for a category name. It is best if you use a meaningful category name. I have used the category name "Example Class".

Once you have provided a category name it will be immediately created. However, note that it will add the category at the bottom of the list of categories or, if you have selected (highlighted) an existing category, immediately above that category. This means that if you have accidentally selected a category in the middle of the list, your new category will be added in the middle of the category list. It is easier to find your own categories if they are not mixed up with other categories. It is therefore advisable to make sure that no categories are selected when you create a new one.

Next define a new class. You can do this by filling out the template in the bottom window (commonly called the code view) of the System Browser to mirror the following:

```object subclass: #Person
instanceVariableNames: ' name age '
classVariableNames: ''
poolDictionaries: ''
category: 'Example Class'
```

That is, define the class Person as a subclass of Object and give it two instance variables name and age. (Note that if you have called your class category something other than " Example Class " the category field will be different).

Notice in Visualworks, that the template fills in the superclass, the class name and the variable fields with default values, e.g.:

```nameOfSuperclass subclass: #NameOfClass
instanceVariableNames: 'instVarName1 instVarName2'
classVariableNames: 'ClassVarName1 ClassVarName2'
poolDictionaries: ''
```

If you do not delete these fields, they will be included in the compiled class. For example, it is easy to find that you have four instance variables and two class variables. The additional variables having names such as instVarName1 and ClassVarName1.

If you have defined the new class correctly, then at this point your browser should look like that in Figure 8.1. Do not worry if the list of class categories in the right most window is different, the important points are that the class definitions match and that the highlighted text is the same.
<figure><img src="image_41.png" /><figcaption>Figure 8.1: Defining a new class</figcaption></figure>

### 8.2.2 Defining a class comment

The next thing you should do is to define the class comment. It is generally a good idea to do this, but if you wish to omit it, it will not affect how your class operates. If you do wish to add a comment then select the **comment** option off the menu presented from the right mouse button (middle on a three button mouse) in the class window. The comment I have defined is illustrated in Figure 8.2. Once you have typed in the text of your comment you must “accept it”. This can be done from the right mouse button (middle button on a three button mouse).

This is a good example of some common uses of the class comment. Note that I have not only specified the intention of the class, what the instance variable of the class are and what they take, but also how the class might be used.

## 8.3 Defining methods

Now you are ready to start defining methods for the class. The first method you should define is one which will be used to initialize the instance's state (i.e. initialize the instance variables). Traditionally, methods such as initialize, which are not intended for general use, are placed in a method protocol called “initialize-release”. If you look at the methods defined in the system classes you will note that similar names are used for protocols possessing similar types of methods, “initialize -release” is an example of such a protocol name. You should therefore place the method `initialize` within the protocol `private`.

### 8.3.1 The “initialize-release” protocol

To create the initialize method, you will first have to create the message protocol in which to place the method definition. To do this, you use the **add** option off the right button menu (middle if you have a three button mouse) in the message protocol window. This is the third window along in the System Browser. This causes a dialog to be displayed requesting the name of the new protocol. This will either be blank or contain the name of the last protocol you visited. If it is not *initialize-release*, then type in *initialize-release*. Again the new protocol will be either placed at the end of the list of protocols or it will be placed above the protocol currently selected (if one is selected).

You will then be presented with a new message protocol in the message protocol window. This protocol will be selected and the following template will be displayed in the code window:

```
message selector and argument names
  "comment stating purpose of message"

  | temporary variable names |
  statements
```
You can now define the `initialize` method. In this case, the method is very simple as it merely sets the instance variable `age` to 0 and `name` to a null string `''`. To do this type in the following method definition into the code view window, replacing the method template displayed there.

initialize

"This method is used to initialize any variables etc."
self name: ''.
self age: 0.

Once you have typed in the method you can **accept** it. When you do so, the system will inform you that the two methods `age:` and `name:` are undefined<fnref n="8" />. From the dialogs you should select the **proceed** option as we will define these methods later. Figure 8.3 illustrates the System Browser at this point.

<figure><img src="image_42.png" /><figcaption>Figure 8.2: Defining a class comment</figcaption></figure>

### 8.3.2 The “accessing” protocol

Now we will define the “accessing” protocol. Again this is a protocol name which is widely used within the system classes. If you adhere to the standard protocol names you will find it easier to follow the system classes (and other people’s classes). Define the new protocol as before and then define input the following method.

age

"This is an example accessor method"
^age

This is an example of another feature of Smalltalk style, that is, if you write a method to return an instance variable's value, you do not call it *returnAge*, instead you give it the same name as the instance variable; in this case `age`. The system is able to determine whether you mean the instance variable or the method from the way you call it. These methods are termed *accessor methods*.

The next method will be called `age:`; this illustrates another Smalltalk style element in this example. This method updates an instance variable. The method is therefore given the same name as the instance variable but with a trailing colon. We do not call it `setAge` or `updateAge`. You may not like

<footnote n="8">⁸ Note that if you have objects in the system which define these messages, then VisualWorks will not tell you that they are undefined, even though they are undefined for Person!</footnote>
this convention at the moment, however it is used throughout Smalltalk, it is therefore advisable to use it.

```ruby
age: anInteger
"This method sets age."
age := anInteger
```

This method illustrates another feature of Smalltalk programming style, the use of class names as parameter variable names. For example, in this method we are expecting one parameter. Smalltalk is untyped, therefore the contents of this parameter could be anything. However, the programmer of this method has indicated to us that they expect the value passed into the method to be an integer. At least now, if the system encounters a run time error and we enter the debugger, we can see if the contents of anInteger is an integer or not. If it is not, then we may have found the source of the problem.

<figure><img src="image_43.png" /><figcaption>Figure 8.3: The System Browser displaying part of the Person definition</figcaption></figure>

The equivalent methods for accessing and updating the value of the instance variable `name` are presented below. They are very simple and should not come as a surprise. They are therefore merely listed and are not discussed in detail.

```ruby
name
"This retrieves the contents of name."
^name
```

```ruby
name: aString
"This sets the contents of name."
name := aString
```

### 8.3.3 The “updating” protocol

Having defined all the methods for the “accessing” protocol, we will now define a new protocol called “updating”. This protocol should be created in exactly the same way as the last two protocols. This protocol is intended for methods which cause a change in the state of the object due to some calculation or operation. This protocol will be used to define the `birthday` method (see Figure 8.4).

<figure><img src="image_44.png" /><figcaption>Figure 8.4: Defining the birthday message</figcaption></figure>

This last method uses the other methods in order to change the current value of the instance variable `age` and to print a meaningful message to the user.
## 8.4 Creating an instance

As was suggested in the class comment, create an instance of the class and send it some messages. You can do that by typing the code in Figure 8.5 into the Workspace and selecting it. Then use the **do it** option off the right mouse button menu (middle mouse button if you have a three button mouse).

The result of running this code should be that the following is printed into the Transcript:

```
0
Bob was 0 but now is 1
```

Once you have done this and are happy with what is happening, why not try and change the method definitions or add a new instance variable called `address` and define the appropriate methods for that variable.

<figure><img src="image_45.png" /><figcaption>Figure 8.5: Creating an instance of Person</figcaption></figure>
# 9. Control and Iteration

## 9.1 Introduction

This chapter introduces how control and iteration are achieved in Smalltalk. To do this a number of concepts which are unique to Smalltalk are also discussed (such as the block object). To simplify this process for the reader, equivalent C constructs are illustrated beside Smalltalk constructs (where they exist).

The remainder of this chapter is structured in the following manner. Section two introduces the concept of cascading, Section three discusses blocks and Section four describes the control structures available in Smalltalk.

## 9.2 Cascading

Cascading is a syntactic form that allows multiple messages to be sent to the same object. The aim of this is to reduce the need for tediously repeating the same object over and over again, because a whole set of messages must be sent to that one object. The intention is to produce more concise code which is easier to read, and to avoid the need for additional temporary variables.

Cascading is achieved by using the semicolon delimiter. This is slightly confusing for those coming from a C or Ada background as the semicolon is used there as a expression terminator r. Instead, in Smalltalk, it should be read as send the next message to the same object as the last message. For example, the expressions:

Transcript cr.
Transcript tab.
Transcript show: 'Hello World'.
Transcript cr.

can be written in a shorter form as:

Transcript cr;
tab;
show: 'Hello World';
cr.

The programmer should be wary of using the cascade mechanism. Although it was intended to simplify code, it can often have the opposite effect. For example, in a very long cascaded expression, which appears all on the same line, it can become difficult to determine exactly what is happening. It is therefore often the case that a set of message expressions are easier to understand when they are not written using cascading.

## 9.3 Blocks

### 9.3.1 Block definition and evaluation

Earlier in this book you were told to treat Blocks as the same as Begin/End constructs in Pascal and ADA or {}'s in C. This was, however, not exactly the truth. They are in fact objects in their own right (and are instances of BlockClosure) which represent code that can be executed (or evaluated) now or at a later date. Block expressions therefore describe deferred activities.
Blocks are represented by square brackets `[ ]` and obviously have a very different meaning to round brackets `()`.
This can be yet another point of confusion for those new to Smalltalk. The round brackets will return the result of evaluating what they contain, at the point at which the expression is encountered. The square brackets will return a block object. This block object will contain zero or more statements. These statements will only be executed when the block is *evaluated*. This is achieved by sending the message `value` to the block. For example:

`[counter := counter + 1] value.`

However, if we don't want to execute the statements in this block until later, we don't have to. In fact as the block is actually an object, we can assign the block to a variable. Then when we are ready we can evaluate the block held by the variable. For example:

```myBlock := [counter := counter + 1].
...
myBlock value.
```

Thus when a block expression is encountered, the statements enclosed are *not* executed immediately. In other words, the contents of the square brackets are stored until a value message is sent to it. Thus in the above example, `counter` will only be incremented when the message `value` is sent to `myBlock`.

It is important to note that the block will execute within the context in which it was defined and not necessarily in the current context. This means that the value used for `counter` will be the value it had wherever the block was created.

As was explained in Chapter 6 all expressions return a value. In the case of a block, when it is evaluated, the result returned is the result of evaluating the last expression in the block. Thus the value 18 is assigned to the variable `result` in the following example:

`result := [2 * 4. 3 * 6].`

### 9.3.2 Block parameters

Blocks can also take parameters. This is done by preceding the statements in the block by a vertical bar and the input parameter. This parameter has a preceding colon. For example:

`[:counter | counter * 2.]`

This block takes one input parameter and possesses a single statement which multiples the input value by 2. This can then be evaluated with a single parameter. This is achieved by sending the block the keyword message `value:`; the argument is the value to bind to the block parameter `counter`. For example:

`[:counter | counter * 2] value:10.`

This would produce the value 20. It is possible to pass in more than one parameter to a block. For example, if we want to specify that a block takes two parameters, then we could use the following definition:

`[:x :y | x * y]`

This block would be evaluated using the `value:value:` message.

`[:x :y | x + y] value: 10 value: 20.`

The same number of arguments must appear in the block and the message. In fact there are also `value:value:value:` and `value:value:value:value:` messages for blocks which take three and four arguments. There is also a `valueWithArguments:` message for blocks taking more than four arguments.
### 9.3.3 Block temporary variables

Blocks can also possess their own temporary variables. These variables are defined between two vertical bars and after any input parameters. For example:

```
[:x |
|temp1 temp 2|
temp1 := x.
temp2 := temp1 * 3.]
```

A block can actually have up to 256 temporary variables in VisualWorks. However this figure does vary from implementation to implementation.

### 9.3.4 Typical block usage

Finally, blocks are often used for control structures:

```
aNumber even
    ifTrue: [aString := 'even']
    ifFalse: [aString := 'odd'].
```

Effectively this means send the message value to one of the blocks, depending on the result of testing `aNumber` to see if it is even or odd. We shall look at the use of blocks in condition and iteration statements later in this chapter.

## 9.4 Control structures

### 9.4.1 Flow of control

As has previously been mentioned, the `if-then` constructs in Smalltalk are actually methods defined on the class `Boolean`. However, ignoring that issue for a moment, the actual use of the structures is very straight forward. The basic formats of the `if-then` expression are:

```
aBoolean
    ifTrue: aBlock
    ifFalse: anotherBlock.
```

```
aBoolean
    ifTrue: aBlock.
```

```
aBoolean
    ifFalse: aBlock
    ifTrue: anotherBlock.
```

```
aBoolean
    ifFalse: aBlock.
```

The boolean object is often generated dynamically via some form of logical test (e.g. `a < b`). That is, the first operation is to create the boolean object, which is then sent the message `ifTrue:ifFalse:`. This is why the boolean test is often bracketed with round brackets. Then if the value of the boolean is true, the code in the `ifTrue` block is executed, if it is false the code in the `ifFalse` block is executed. Consider the following example:

C version
```c
if (count < 100)
    count++;
else {
    printf("Overflow\n");
    count = 0;
}
```

(count < 100)
    ifTrue: [count := count + 1]
    ifFalse: [Transcript show: 'Overflow'. Transcript cr. count := 0.]
```

In both cases the code increments the value of a counter if its maximum count has not been reached; if the maximum count has been reached, the code resets the counter and prints an error message. Nested `if-then` statements can be constructed as in any other language. For example, in Smalltalk:

```
(count < 100)
    ifTrue: [(index < 10)
        ifTrue: [....]
        ifFalse: [.....]]
```
```
ifFalse: [...]
```

However, it is easy to get confused and therefore one must be careful. A facility not provided explicitly by Smalltalk is the `if -then-else-if-else` type of structure. For example, in C it is possible to write:

```c
if (n < 10)
    printf("less than 10");
else if (n < 100)
    printf("greater than 10 but less than 100");
else
    printf("greater than 100");
```

In Smalltalk it is necessary to nest `ifTrue`: `ifFalse` constructs as above. However, it is easier to see if you have a dangling `else` problem as the built-in formatter available in the various browsers can be used to see if the code formats in the expected manner.

There is also no such thing as a case statement in Smalltalk. Instead, the functionality required is usually achieved using a dictionary.

```map
map := Dictionary new.
map at: $^ put: [Transcript show: 'It is a caret'].
map at: $> put: [Transcript show: 'It is greater than'].
map at: $< put: [Transcript show: 'It is less than']
:
result := (map at: char) value.
```

This is the Smalltalk equivalent of the following in C:

```c
switch (char) {
    case '^':
        printf("It is a caret");
        break;
    case '>':
        printf("It is a greater than");
        break;
    :
}
```

This is actually an example of how Smalltalk is truly object oriented. That is, even what would be considered standard control structures in other languages, have to be implemented by using objects and message passing. A point to note is that the control structures which do exist in Smalltalk may at first seem to be similar to the control structures in other languages. However, this is both persuasive and misleading. They are of course messages to objects (e.g. true, false or a block object). Internally they perform something which is similar in nature to what we have done above for the `switch` statement. If you find this confusing, don't worry, but if you can see what is meant by this then you have gone a long way down the round to understanding Smalltalk.

## 9.4.2 Repetition

Iteration in Smalltalk is accomplished with the `timesRepeat:`, `whileTrue:`, `whileFalse:` and enumerating messages (such as `do:`). The enumerating messages will be considered in more detail when we discuss the collection classes. For the moment we shall limit ourselves to a simple form of the `do:` message and the `timesRepeat` message. In the next subsection we will consider the `while`-based messages.

Like their counter parts in other languages, the `timesRepeat:` and `do:` messages repeat a sequence of instructions a fixed number of times. In C, this construct is provided by the `for` loop. For example:

```c
for (n = 1; n <= 10; n = n + 1)
    printf("%3d", n);
```

This assigns `n` the initial value 1, it then repeats while the middle test is true during which the last expression increments the value of `n` after each execution of the `printf` statement. In Smalltalk this can be achieved using the `do:` message. This message is actually sent to an interval (which is discussed elsewhere):

```
(1 to: 10) do: [:n | Transcript show: n printString]
```
The brackets round the 1 to 10 are required, because we create an interval object with the range 1 to 10 which is sent the message `do:` with a block as its parameter. However, it has exactly the same effect as the C version presented above.

It should be noted that what is happening here is that the block object passed as the parameter to the `do:` message actually takes a parameter itself. In fact it is passed the values 1 through 10 in turn. Each value is the `n` bound to the block variable `n`. This is achieved by sending the message `value:` with a different element of the interval to the block within the `do:` message.

In situations where you merely require a piece of code to execute a given number of times, without the requirement to reference any loop variable, it is possible to use a very simple control structure. This structure is the `timesRepeat:` message. This message is sent to an integer and causes the associated block to be executed `n` times, where `n` is the integer the message is sent to. For example:

10 timesRepeat: [Transcript show: 'Hello'; cr.].

this will cause Hello to be printed ten times in the Transcript window.

Blocks with arguments are also used to implement functions to be applied to all elements of a data structure. For example (using an array):

sum := 0.
#(3 5 8 4 6) do:
    [:item | total := total + (item * item)]

The variable `item` takes the value of each element in the array. The result of these expressions is the sum of the squares of the values in the array. This is a very useful construct.

### 9.4.3 While loops

The while loop exists in almost all programming languages. In most cases it has a basic form such as:

while (expression)
    statement

Because in Smalltalk a while loop is achieved by sending a message to an expression the format is slightly different. In Smalltalk the basic format is:

[condition] whileMessage:
    [statements]

where *condition* is the control expression in the form of a Block Context. *Statements* are the controlled set of Smalltalk code also in a block context. The control of this statement is determined by the *whileMessage* that can actually take a number of forms which will be discussed below.

The basic while messages are the `whileTrue:` and `whileFalse:` messages. For the `whileTrue:` message, if the value of the control expression in the receiving block is true, then the controlled statements are executed. After this the control expression is evaluated again and so on. This is actually achieved in Smalltalk by sending the receiver block the message `value;` if the response is true, then the argument block is sent the message `value`. This repeats until the receiver block answers `false`.

For example:

C Version

n = 1;
while (n <= 10)
{
    printf("%3d", n);
    n++;
}

Smalltalk Version

n := 1.
[n <= 10]
whileTrue:
    [Transcript show: n.
     n := n + 1].

This should be read as: The block object is sent the message `whileTrue:` with one parameter which is also a block object. If the first block object evaluates to true when sent the message `value`, (i.e. if the value of `n` is less than or equal to 10) then the message value is sent to the second block object. If this message is sent, then the current value of `n` is printed in the Transcript and is then incremented by one. This is repeated until the first block returns `false` (i.e. `n` = 11). Note, as in any other language `n` must be
assigned an initial value before the condition expression. This is because the while message begins by evaluating the control expression, if no initial value is provided for n it will default to nil. Comparing nil with a numeric value will result in an exception being raised.

As you can see the equivalent C code is not that different, but the semantic meaning is completely different.

The `whileFalse:` message has exactly the same format as the `whileTrue:` message. The only difference is in the condition used to decide whether to evaluate the second block or not.

```
n := 1.
[n > 10] whileFalse:
    [Transcript show: n.
     n := n + 1].
```

In some cases we want to do all the work in the receiver block. These versions of the while message can be viewed as being similar to the do statement in C. To support such a feature there are two versions of the while loop which do not require the second block to be provided. These are the `whileTrue` and `whileFalse` messages (note the absence of the ':'). For example:

```
C Version

do {
    scanf("%d", &n);
    printf("%d\n", n);
} while (N < 1000);
```

```
Smalltalk Version

[n := Transcript getNumber.
Transcript show: n; cr.
n < 1000] whileTrue.
```

Both of these segments of code are expected to read in a number, print it back out and then check to see if it is less than 1000. If it is the sequence of steps is repeated, otherwise the loop is terminated. For example, this could be used to ensure that some input is in the desired range.

## 9.5 Summary

You now know virtually everything about Smalltalk except the classes which make up the very large library of reusable components available to the developer. You have learnt the basics of the language in chapter 6 and in this chapter you have learnt about cascading, blocks and their use in iteration constructs. You have also learnt about conditional statements and their use of blocks. You are now ready to explore the class structure in Smalltalk.

## 9.6 Further Reading

As ever, the Hopkins and Horan book [Hopkins and Horan 1995] is a good reference source for the Smalltalk language. Other useful books are [Lalonde and Pugh 1991] and [Goldberg and Robson 1989].

# 10. The Collection Classes

## 10.1 Introduction

This chapter discusses probably the most used class hierarchy in Smalltalk; the collection class hierarchy. The collection classes are the basis upon which data structures are constructed in Smalltalk. Section two introduces the collection class hierarchy and the common functionality provided by all collection classes. Section three presents a decision tree to help identify the most appropriate collection class to use. Sections four, five and six present the `Bag` class, the `Set` class and the
OrderedCollection class (respectively). Section seven then presents how the OrderedCollection class can be used to construct Stack and Queue classes.

## 10.2 The Collection class hierarchy

A *collection* is a group of objects (these objects are called the *elements* of the collection). Collections are the Smalltalk mechanism for building data structures of various sorts; it is therefore important to become familiar with the collection hierarchy and its functionality.

Class *Collection* is the abstract superclass of all collections in the system. Figure 10.1 summarizes the collection classes in VisualWorks. Some of the classes illustrated are abstract classes on which others build. In fact the collection class hierarchy is a classic example of the use of abstract classes and how they can be used to group together functionality as well as indicate what is expected of subclasses. Now might be a go od time to stop and examine the collection class itself. Abstract classes in this hierarchy include:

* *Collection*. This is the abstract root class for the whole hierarchy.

* *SequenceableCollection*. This is the abstract class for collections which have a defined sequence. That is, the subclasses of this class support the notion of having an *order* associated with the elements.

* *ArrayedCollection*. This is the abstract class for those classes which have an array like behaviour. That is, subclasses of this class support the notion of an externally defined ordering.

<figure><img src="image_46.png" /><figcaption>Figure 10.1: Part of the collection hierarchy in Smalltalk</figcaption></figure>

The concrete classes in the collection class can either be ordered or unordered and may or may not possess duplicates. Concrete classes which are unordered include:

* *Bag*. A *Bag* contains all the objects put in it, in no particular order. Duplicate objects are permitted.

* *Set*. *Sets* contains all the elements put into it, in any order. Duplicates are not kept; adding equal objects many times results in only one such object in the *Set*.

* *Dictionary*. Class *Dictionary* is a subclass of *Set* and represents a set of *associations* between pairs of objects.

Concrete classes which are ordered include:
* **OrderedCollection**. A collection where the ordering is given by the order in which elements were added.

* **Array**. A collection which provides array like behaviour.

* **String**. An indexed collection of **Characters**.

* **SortedCollection**. A collection of objects, which are sorted according to an ordering defined in the instance of SortedCollection.

* **Symbol**. A subclass of **String**. All symbols are unique, while there can be two different Strings containing the same characters.

* **Text**. A class which understands a notion of a collection of *fonts* associated with a string.

A relatively new class which incorporates some of the more useful features of the **Array**, **OrderedCollection** with **SortedCollection** classes is the **List** class.

The basic operations that are performed by the collection data structures **List** and **OrderedCollection** include adding and removing elements, determining the size of the collection, querying the presence or absence of elements and iterating over the elements.

## 10.3 Choosing a Collection class

It can sometimes be confusing for those new to Smalltalk to decide which collection class to use. Some make the mistake of always using an array (because it is similar to the constructs that they are used to). However, this is failing to understand the way one should work with collections (data structures) in Smalltalk. To this end the following decision tree may be of use.

<figure><img src="image_47.png" /><figcaption>Figure 10.2: Selecting which Collection class to use</figcaption></figure>

The most commonly used collection classes are, **Array**, **SortedCollection**, **OrderedCollection**, **List**, **Dictionary** and **Set**.

## 10.4 The Collection class

The collection class is the abstract superclass which acts as the root of all collection classes. It provides facilities for creating instances of a collection class, adding an element to a collection, accessing elements in a collection, removing an element from a collection and indicating the size of the collection. It also provides facilities which allow an operation to be applied to all elements of the collection (in a similar fashion to the mapcar function in Lisp). It also provides a number of conversion routines which allow one collection to be converted into another.

With one or two exceptions (e.g. **ByteArray**) any object can be stored into any collection. The only message that these operations must be able to respond to is `=` (although objects to be placed in a **Sorted** collection must also respond to `<=`). This means that a collection can be a very flexible way of
holding other objects. Typically, collections are used as data structures in Smalltalk systems. They can also be used as temporary holding places for groups of calculations, results, operations etc.

The `Collection` class assumes that a new subclass will provide at least the following:

* `add`: This adds an object to the collection

* `remove`: `ifAbsent`: This removes an object from the collection. If it is not present in the collection, the block provided as the parameter to `ifAbsent:` is evaluated.

* `do`: This applies the associated block to each element in the collection

* `copyEmpty`: (if the subclass possesses named instance variables). This creates a copy of the receiving collection which contains no elements.

The `Collection` class defines the common protocols to which all types of collection are expected to respond. For example, objects may be added to collections using:

* `aCollection add: anObject` Subclasses redefine this message such that it will add a single instance of `anObject` to the collection. In some classes this is dependent on the current contents of the collection (e.g. class `Set`).

* `aCollection addAll: oldCollection` Add each element in `oldCollection` to `aCollection`. This method uses `add:` and therefore does not need to be redefined in a subclass.

* `size`. The current size of the collection (i.e. the number of objects it contains) may be obtained using the `size` message: `aCollection size`.

Objects may be removed using one of the following:

* `aCollection remove: oldObject`. Remove the first element which equals `oldObject`

* `aCollection remove: oldObject ifAbsent: aBlock`. Subclasses redefine this method. The intention is that the method will remove the first instance of `oldObject`. They will run `aBlock` if that object is not present in the collection.

* `removeAll: aCollection`. This method removes all of the element contained in `aCollection` from the receiving collection.

The `Collection` class also defines a range of test methods which can be used to identify the current state of a collection or determine if an object is a member of a collection. The test operations supported include:

* `aCollection includes: anObject`. This tests whether an element is currently a member of a collection. This method uses the `=` test.

* `aCollection empty?`. This message returns true or false depending on whether the collection contains any objects or not.

* `aCollection occurrencesOf: anObject`. This message returns the number of times `anObject` is present in the collection. Again this uses the `#=` test.

Additional protocols are implemented by subclasses to support operations suitable only for that class. For example, `OrderedCollection` supports `first`, `atFirst; after:` and `add: before`: while arrays understand `at:` and `at:put:`.

## 10.5 Bag

Abstractly a `Bag` can be considered to be any collection of objects, which can be of any class; these objects are the elements of the `Bag`. It is a general place holder for collections of objects. There is no order assumed. It is the most general form of collection available in Smalltalk. (In many implementations each entry in the bag is actually an association which indicates the object and the number of times it has been placed in the bag. This is intended as a performance enhancement and is normally transparent to the user.)
If you are confused by this description of a bag, think of it as a shopping bag. At a supermarket, you pick objects up from the shelves and place them in your shopping bag. For example, you pick up a pint of milk, a box of corn flakes, a packet of biscuits, three bags of potato crisps, and a few bananas (see Figure 10.3).

<figure><img src="image_48.png" /><figcaption>Figure 10.3: A shopping bag</figcaption></figure>

Each of the objects in the bag is a different type of thing, with different characteristics etc. There is no particular order to them, they will have moved about in the bag while you were shopping and while you brought them home. When you reach into the bag at home to remove the objects, the order in which they come out will not be predictable. If you think of a bag collection in these terms then you will not be far off the mark.

As with any other class we create an instance of Bag by sending the message new to the class Bag.
For example:

```
| temp |
temp := Bag new.
```

The bag object responds to the add: message to add objects as well as the add:withOccurrences: messages which can be used to add an object *n* times. For example:

```
temp add: 'John'.
temp add: 'Hello' withOccurrences: 2.
```

At this point the bag object will contain three objects, the string 'John' and two copies of the string 'Hello'. We can examine the contents of the bag using the inspect message, for example:

```
temp inspect.
```

You will notice that the bag object does not record the objects in the order in which they were added. Instead, the order is not specified (it is actually determined for efficiency). You will also notice that there are instance variables numbered 1 - 7. This is because collections are a special type of object whose instance variables are defined dynamically as and when required. They are termed "variable" classes.

It is also possible to remove objects from a set using either the `remove:` `ifAbsent:` message or the `removeAllOccurrencesOf:` `ifAbsent:` message. The first is used to remove a single reference to an object, while the second is used to remove all references to an object. In both cases a block must be supplied which is executed if the object is not a member of the bag. For example:

```
temp remove: 'Paul' ifAbsent: [].
temp remove: 'Paul' ifAbsent: [Transcript show: 'No Record of Paul'].
```

In the first example, if the string 'Paul' is not in the bag then the empty block will be executed, which will result in nothing happening. In the second example, a message will be printed to the Transcript.

## 10.6 Set

The class `Set` is basically the same as the class `Bag`, with the exception that it does not allow duplicates. That is, it is only possible to hold a single reference to an object in a set. For example, try the following out in a Workspace:
```
| temp |
temp := Set new.
temp add: 'John'.
temp add: 'Paul'.
temp add: 'Peter'.
temp add: 'John'.
temp inspect.
```

You will find that only one occurrence of the string 'John' was added to the set. The second addition was ignored.

There is also a version of the collection class `Set` called `IdentitySet`. This type of set performs an identity test to determine if an object is a duplicate or not. That is, it uses the `==` test rather than the `=` test. This means that rather than an object having the same value as an object already in a set, it must actually **be** that object. If it is only equivalent then the object will be added to the set. In this way it may appear that duplicates have been added to the set. However, they are not the same object and are therefore allowed.

The `IdentitySet` can be useful if you know that duplicate elements to be added to the set will be the same object. In such cases the Identity set can be used as it is more efficient than the standard set.

## 10.7 OrderedCollection

The `OrderedCollection` class can hold any type of object. It does so in a specified order. That order is determined by the order in which objects are added to the `OrderedCollection` instance. An instance of `OrderedCollection` is created by using either `new` or `new:`. The second version of `new` allows an integer to be provided which indicates the maximum size of the collection required. This can be useful in situations where this number is known and time is optimal. That is, it is not necessary to waste time incrementally growing the collection.

`OrderedCollection` can be used in situations where the order in which the objects were added to the instance must be preserved. For example, try out the following example of using an `OrderedCollection`:

```
| x |
x := OrderedCollection new.
x add: 'one'.
x add: 'two'.
x add: 'three'.
x inspect.
```

You will find that the strings 'one', 'two' and 'three' remain in the order in which they were added (unlike instances of `Bag` and `Set`).

There is a wide range of order related messages which allow objects to be added and accessed with reference to the order in the `OrderedCollection` instance. For example, it is possible to access an object "before" or "after" another object by using the `before:` or `after:` messages, e.g.:

```
x after: 'two'.
```

It is also possible to add an object either before or after another object. For example:

```
x add: 'five' after: 'one'.
x add: 'six' before: 'three'.
```

To remove an object from the collection use `remove:ifAbsent:`, this removes the first instance of the object specified in the collection. If the object is not present, then the `absent` block will be executed. For example:

```
a remove: 'John' ifAbsent: [Dialog warn: 'John not present'].
```
The OrderedCollection class can be used to construct a Stack or Queue class. An example of how to do this is presented in the next section. Notice how little code has to be written and how much is inherited.

# 10.8 Stack and queue classes in Smalltalk

In this section we will work through an example illustrating how we can define new collection classes (data structures). We shall put both classes we will define into a class category called "Additional Collections".

## 10.8.1 The Stack class

The first class we will define is the `Stack` class. The class definition of the `Stack` is illustrated below<fnref n="9" />. Note that we are making `Stack` a subclass of `OrderedCollection`. This is because the elements of a stack are ordered, and may be duplicated within the stack. Also note that we are not defining any new instance variables. The functionality of the `Stack` will come solely from extending the interface, the structure of the class will be completely inherited from the `OrderedCollection` class.

```
OrderedCollection variableSubclass: #Stack
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Additional-Collections'
```

As before I am also providing a class comment (see Figure 10.4). Again it is up to you to decide whether you wish to provide one as well (although I strongly recommend doing so - it is a good habit to get into).

<figure><img src="image_49.png" /><figcaption>Figure 10.4: The Stack class comment</figcaption></figure>

<footnote n="9">⁹ As OrderedCollections are variable in size the variableSub class: class creation message is used. Don't worry too much about this as the tools provided with environments such as VisualWorks ensure that the appropriate message is always used.</footnote>
Next we will define a message protocol called "operations". It is within this protocol that we will define all the methods which will provide the functionality of the Stack. These methods will be `push:`, `pop` and `top`.

The `push:` method is used to push something onto the top of the stack. It takes one argument, (an object) and adds it to the top of the stack. To do this it uses the `addLast:` method inherited from `OrderedCollection`.

```kotlin
push: newObject
    self addLast: newObject
```

Next we will define the `pop` method. This method removes the top element from the stack and returns it as the result of evaluating `pop`. Again it uses methods inherited from `OrderedCollection` to do this.

```kotlin
pop
    self isEmpty
        ifTrue: [^nil]
        ifFalse: [^self removeLast].
```

Finally, we will define the method `top`. This method is like `pop`, except that it does not remove the top most element from the stack. To do this we use the message `last` inherited from `OrderedCollection`.

```kotlin
top
    self.isEmpty
        ifTrue: [^nil]
        ifFalse: [^self last].
```

This class is an excellent example of why Smalltalk is so powerful. We have defined a class which provides the functionality of a `Stack` (no matter what the contents of that stack will be) in just a few lines of code. Consider the amount of work required to achieve the same result in a language such as Pascal or C (without purchasing additional libraries).

## 10.8.2 The Queue class

This class definition is very similar to the `Stack` example, it is therefore presented here with little additional comment.

```kotlin
OrderedCollection variableSubclass: #Queue
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Additional-Collections'
```

Again a class comment should be defined. This is left an excersie for the reader. The methods should again be placed in a protocol called "operations". Each of the methods are listed below.

```kotlin
add: newObject
    self addLast: newObject.

delete
    self.isEmpty
        ifTrue: [^nil]
        ifFalse: [self removeFirst].

next
    self.isEmpty
        ifTrue: [^nil]
        ifFalse: [^self first].
```

The state of the class definition at this point is illustrated in Figure 10.5.
## 10.9 Summary

In this chapter you have encountered for the first time, one of the most important class hierarchies in Smalltalk. The various collection classes will form the basis of the data structures you build and will be the corner stone of most of your implementations. So far you have looked at *Bags*, *Sets* and *OrderedCollections*. For those of you coming from a Lisp style language these concepts won't have seemed too strange. However, for those of you coming from languages such as C, Pascal or Ada you may well have found the idea of a *bag* and a *set* quite bizarre. Stick with them, try them out, implement some simple programs using them and you will soon find that they are easy to use and extremely useful. You will very quickly come to wonder why every language doesn't have the same facilities!

<figure><img src="image_50.png" /><figcaption>Figure 10.5: The System Browser after the "next" method has been defined</figcaption></figure>

## 10.10 Further reading

Almost any good book on Smalltalk includes a detailed discussion of the collection classes. However, particularly good references can be found in [Lalonde and Pugh 1991]. Useful references for the Queue and Stack classes can be found in [Goldberg and Robson 1989].
# 11. Further Collection Classes

## 11.1 Introduction

This chapter continues the discussion of the collection class hierarchy. It concentrates on the ordered collections and builds on the previous chapter. Sections two, three and a d four present the `SortedCollection` class, the `List` class and the `Interval` Class. The `Array` class, `Dictionary` class and `String` class are presented in Sections five to seven. Section eight describes how to iterate over collections while Section nine explains how to convert between collections. Figure 11.1 illustrates the relationships between some of the ordered collection classes.

<figure><img src="image_51.png" /><figcaption>Figure 11.1: Some of the ordered collection classes</figcaption></figure>

## 11.2 SortedCollection

A `SortedCollection` is a collection class in which the order of the elements is determined by a specified sorting criteria (for example `x[i] < x[i+1]`). This is specified by the sort block associated with every `sortedCollection` object. That is, the ordering is defined by a special block of code (for example, `[:x:y | x>= y]`). This block can be replaced by the user of the class so that any type of ordering can be applied to the objects with in the collection. Why not browse the class using the class browser. Try and find out what type of sorting algorithm is being used.

Try out the following in a Workspace:

```
| x |
x := SortedCollection new.
x add: 5.
x add: 6.
x add: 7.
x add: 1.
x inspect.
```
This is a very powerful class which greatly simplifies the production of ordered lists of information. You can change the block controlling the sort by sending the message `sortBlock:` to the `sortedCollection` instance with a new block definition.

## 11.3 List

The `List` class is a recent addition to the collection classes in VisualWorks (which is not yet available in other implementations of Smalltalk such as Visual Smalltalk). The `List` class combines some of the more useful features of the `Array`, `OrderedCollection`, `SortedCollection` classes and the `Model` class. The order of its elements is initially determined by the order in which the elements are added (as in `OrderedCollection`). These elements can then be accessed via an index (as in `Array`). However, the elements can also be sorted using either the default ascending order, or a custom sort block can be provided (as in `SortedCollection`). In addition a `List` keeps a record of dependents to which it should send updates (as in class `Model`). However, as we have not yet looked at the `Model` class, we will ignore this part of the class's operation.

The set of features provided by this class make it one of the most widely used types of collection, in some cases supplanting the older `OrderedCollection` and `SortedCollection` classes. It responds to a combination of the Ordered and Sorted Collection class protocols. Therefore it understands `after:`, `before:`, `sort`, `sortWith:`, `add:`, `add:after:` and `add:before:`. It also responds to `addLast:`, `addFirst:`, `remove:ifAbsent:`, `removeFirst`, `removeLast` etc.

To create a new instance of class `List` use either `new` or `new:` depending on whether you wish to specify an initial size or not.

For example, try this out in a Workspace.

```pascal
| temp |
temp := List new: 10.
temp add: 'John'.
temp addFirst:'Paul'.
temp add: 'Peter' before: 'John'.
temp inspect.
```

## 11.4 Intervals

Instances of class `Interval` represent *finite arithmetic progressions*. Such progressions are given by a starting number, a (finite) limit, and a method of computing the next number. Once created, new elements cannot be added or removed from the `Interval`.

Intervals can be created using the class messages:

```
from: start to: stop
from: start to: stop by: step
```

`start`, `stop` and `step` can be any kind of `Number`. Intervals are common enough that a shorthand form has been provided. This shorthand form is achieved by sending `to:` or `to:by:` to a kind of `Number`. For example the following are equivalent:

```
Interval from: 10 to: 100 by: 2
10 to: 100 by: 2
```

These are equivalent to a `for i = 10 to 100 step 2` type loop. However, they actually create an interval containing all the objects to be processed before any further processing occurs. This allows them to be used with a `do` loop.

`Intervals` respond to the message `do: aBlock` by evaluating `aBlock` for each of its values in sequence. Thus, an `Interval` can be used to construct the equivalent of a `FOR` loop. For example:

```
(10 to: 100 by: 2) do: [:each | Transcript show: each printString].
```

This is therefore roughly equivalent to the `C for` loop:
```fortran
for (i = 0; i <= 100; i += i + 2)
    printf ("%d", i);
```

This construction is so common that the `to:do:` and `to:do:by:` are also implemented in `Number` so that the brackets can be omitted if desired. For example:

```fortran
10 to 100 do: [:each | Transcript show: each printString].
```

## 11.5 Array

Essentially the `Array` class is just the same as an array in any language. In an array of `n` locations there will be 1 to `n` indexes in which objects can be stored. For those of you familiar with C, be warned attempting to access the value of location 0 will result in an error. However, one major difference between arrays in languages such as C and those in Smalltalk is that you do not specify the type that each element in the array will take. For example, in C you might specify that an array will be of type `int`. That is all elements in the array will be integers. Instead, an array in Smalltalk can hold any type of object.

Note that it is also not necessary to specify the size of your new array, you can just create a new array (e.g. `Array new`). However, this will typically only allocate you 7 array locations. If you want more, the system will dynamically allocate you with more. However, this is slow and time consuming. If you know you want a hundred locations then say so when you create the array (i.e. `Array new: 100`). Now let's look at an example:

C Version

```c
int x[10]
x[0] := "one";
x[1] := "two";
x[2] := "four";
x[3] := "five";
printf ("%s", x[4]);
```

Smalltalk Version

```
| x |
  x := Array new: 10.
  x at: 1 put: 'one'.
  x at: 2 put: 'two'.
  x at: 4 put: 'four'.
  x at: 5 put: 'five'.
Transcript show: (x at: 4)
printString.
x inspect.
```

Notice that the `at:put:` message is used to put values at specific locations, and the `at:` message is used to retrieve elements. Also notice that it was not necessary to specify the type of the array. As it happens all the elements are strings, but there is no reason why the element at location 3 can't be any type of object at all.

The typical way to access an element in an array is to access it via its index. This means that if you wish to access all the elements in the array `x` in turn you might use a `do loop`. For example:

C Version

```c
for (i = 1; i <= 5; i++)
    printf ("%s", x[i]);
```

Smalltalk Version

```smalltalk
1 to 5 do: [:i |
    Transcript show: (x at: i)].
```

These pieces of code are fairly similar and perform the same function. However, this is not the most appropriate way to process the elements of the array in Smalltalk. Smalltalk provides a number of other constructs (referred to as iteration messages) which are not only more efficient but usually implement the required functionality rather more elegantly. These will be considered in more detail later.

## 11.6 Multi dimensional arrays

Multi dimensional arrays can be created in Smalltalk, and there are two ways of doing this. One provides a two dimensional array (with list like features) which is fixed in size, while the second
provides any dimension size but requires additional programmer support. For example, in C to create a
two dimensional array of 3 by 4 integer elements we could write:

int table [3] [4];

In Smalltalk we can either use a `TwoDList` or create the two dimensional structure manually. For example, if we used the `TwoDList` class:

| aTwoDList |
aTwoDList := TwoDList columns: 3 rows: 4.

We could then place the string 'John' into position 1, 1 using the `atPoint:put:` message. We can then retrieve this string using the `atPoint:` message. Note these messages take a point object as the position. A point object can be created using the `@` form. For example:

aTwoDList atPoint: (1 @ 1) put: 'John'.
Transcript show: (aTwoDList atPoint: (1 @ 1)).

As this class possesses list like behaviour it can be used in a similar manner to an instance of list. For this reason it is often used with the user interface facilities provided in VisualWorks. For example, with the table widget. However, we cannot change the size of a TwoDList once it is created. Nor do we have the ability to use higher dimensions. It is sometimes therefore necessary to manually construct multi-dimensional arrays. For example:

temp := Array new: 3.
temp at: 1 put (Array new: 4).
temp at: 2 put (Array new: 4).
temp at: 3 put (Array new: 4).

We could then access elements of the object in the following manner:

((temp at: 1) at: 1)

If you find yourself having to do this often then it probably means that you are thinking to o procedurally and need to reconsider your design.

## 11.7 Dictionaries

A **Dictionary** is a set of **Associations**, each representing a key-value pair. It is a subclass of **Set**. The elements in a **Dictionary** are unordered, but each has a definite name or **key**. Thus a **Dictionary** can be regarded as an unordered collection of object **values** with external keys. Part of the protocol for dictionaries is listed below:

* `at`: `aKey` returns the value associated with `aKey`.

* `at`: `aKey` `put`: `aValue` puts `aValue` into a dictionary with the external key `aKey`.

* `associationAt`: `aKey` answers with the *association* given by the key (i.e. the value and the key).

* `keyAtValue`: `aValue` answers with the name (key) associated with `aValue`.

* `keys` answers with a **Set** of keys from the receiver.

* `values` answers with a **Bag** of the values in the receiver. Note that values are not necessarily unique (hence they are returned as a **Bag** rather than as a **Set**).

Here is a simple **Dictionary** example you might like to type in and try out.

| x |
x := Dictionary new.
x at: 'John' put: 'jjh'.
x at: 'Myra' put: 'msw'.
x at: 'Chris' put: 'cjr'.
x at: 'Denise' put: 'dec'.
Transcript show: (x at: 'Chris') printString.
Transcript show: (x keyAtValue: 'jjh') printString.
`x inspect.`

This has some similarities to a hash table found in some other languages (e.g. Common LISP) or in libraries available for other languages (e.g. C). The great advantage of Smalltalk is that everyone has the same type of `Dictionary`. In Pascal or C almost everyone would have to re-invent their own or purchase a library to get the same functionality. This, of course, leads to problems of consistency between implementations.

Another form of the `Dictionary` collection also exists. This form is termed the `IdentityDictionary`. Like the `IdentitySet` it uses the `==` test rather than the `=` test. This means that for an object to be returned, the object used as the key must be the same object as was used to create the key and not just an equivalent object. Like the `IdentitySet` it is more efficient that the standard `Dictionary` class and may be used in certain circumstances.

## 11.8 Strings

`Strings` are represented in Smalltalk as collections of characters. Unlike in languages such as C, there is no need to provide special string processing functions such as `strcpy()`. Instead, we can treat strings as collections (and iterate over their contents) or as "strings" in their own right. This is because we are inheriting the collection class (and the `super` classes between the collection class and the class String) methods and are using the methods defined in the class String.

Useful String operations include the concatenation of strings, searching for substrings and pattern matching between strings. For example, `sameAs: aString` answers whether the receiver and `aString` match precisely (ignoring case differences).

To concatenate two strings together use a comma. For example:

`myName := 'John' , 'E' , 'Hunt'.`

Notice that you do not have to specify the length of the string. Remember they are just objects and a variable can hold any object.

Substring operations are essential in any language and Smalltalk provides a variety of features for searching for substrings and pattern matching between strings. For example, the `findString: startingAt: message`. This message searches the receiving string for the string passed as a parameter to the method. For example:

`'John Hunt was here' findString: 'Hunt' startingAt: 1.`

There are two pattern matching methods defined for strings, `sameCharacters:` and `match:`. The first method counts the number of beginning characters which are the same. The second method is more powerful and can include two types of wild card (`#` which can represent any single character and `*` which can represent zero or more characters). For example:

`'Dr. * Hunt' match: 'Dr. John Hunt'.`

This expression *evaluates to true*. There is a variant of the `match:` method which can either ignore or consider case; `match:ignoreCase:` (which takes either true or false as the second argument).

Instances of class `String` also respond to boolean operators such as `<` and `>=`. This is because strings have an ordering (defined by the alphabet). For example:

`'john' < 'Denise'`

There are similar methods for `<=`, `>` and `>=`. Strings can also be converted into lower or upper case using `asLowerCase` and `asUpperCase`. Finally, as strings are types of collection they can respond to the iteration message described above. These can be used for performing some operation on each character in a string in turn.
## 11.9 Iterating over collections

A number of messages are available which allow the same operation to be applied to each element in a collection and in some cases the results of this operation can be automatically collected. These messages are referred to as the iteration messages, they include `do:`, `select: reject:`, `collect:` and `detect:`. For all the messages (except `do:`), the result is a new collection 'just like the receiver'. The elements of this object depend on the criteria specified in the block associated with the message. Note the result can be an empty collection.

### 11.9.1 The do: message

The `do: aBlock` message evaluates `aBlock` for each of the elements in the receiver (a `Collection`). `aBlock` should have one argument. (Note that you have not yet encountered blocks. For the time being treat them as `begin/ends` as in other languages such as Pascal or ADA. We will look at them in more detail later.)

The following example illustrates the use of `do:`

```pascal
count := 0.
letters do: [:each | each == $a ifTrue: [count := count + 1]].
```

This expression counts the number of 'a's in the collection `letters`. The `do` statement iterates over the elements in the `letters` collection. Each element is bound to the temporary variable "each" in turn. It then compares each with the character "a". If the result of this comparison is the object true (remember all expression return an object of some form) then the `ifTrue:` message will execute the code in its associated block.

Compare it with C style code for the same task:

```pascal
count = 0; i = 0;
max_num = length(letters);
for (i = 1, i <= max_num, I++) {
    if (letters[i] == 'a') {
        count++;
    }
}
```

Notice that in the Smalltalk version we did not need to calculate the length of the collection `letters`. Also notice that we only specified the variable `each` which was local to the `do` block within the loop.

### 11.9.2 The select: message

The `select: aBlock` message evaluates `aBlock` for each element in the receiving collection. It returns a result which is a collection object containing the objects selected when the result of evaluating `aBlock` was true. For example:

```pascal
(letters select: [:each | each == $a] ) size
```

This creates a new collection containing only 'a's then counts the number of elements. That is, it only stores the elements of the collection `letters` which return true for the test presented in the block. The equivalent Pascal style code might be:

```pascal
count := 0; i := 0; index := 0;
max_num := length(letters);
for i = 1 to max_num do
    if (letters(i) == 'a') then
        newList(index) := letters(i);
        index := index + 1;
    elif;
endfor;
```

As you can see the Smalltalk construct is rather more elegant.
### 11.9.3 The reject: message

The `reject`: `aBlock` message evaluates `aBlock` for each element in the receiving collection. The result of this message is then a collection `c` containing the objects selected when `aBlock` evaluated to `false`. For example:

```
(letters reject: [:each | each == $a] ) size
```

This will return a collection containing all the elements in letters which weren't the lower case 'a' character. That is, this message returns all the elements in letters which fail the comparison test.

### 11.9.4 The collect: message

With the `collect`: `aBlock` message `aBlock` is again evaluated for each element in the receiving collection. The resulting returned collection object is the same size as the receiving collection. The returned collection contains the result of evaluating the block for each of the elements in the receiving collection. For example:

```
(letters collect: [:each | each == $a] ) size
```

This will return a collection of the same size as letters, with either true or false in each element depending on the outcome of the comparison.

### 11.9.5 The detect: message

In some cases we want to retrieve the first element in a collection which passes some test. The `detect`: `aBlock` message does this for us. It evaluates `aBlock` for each element in the receiving collection and answers with the first element where `aBlock` evaluates to true. For example:

```
letters detect: [:each | (each asUppercase == $A) | (each asUppercase == $B)]
```

This can be extremely useful if you have a collection of records and you need the first one which matches some test.

## 11.10 Inserting into a collection

The `insert` message is a very useful and very efficient operation. For example, if you have a collection of numbers which you wish to total you would either need to iterate over the collection using a `do` loop or convert the collection to an array and use an interval to mimic a Pascal style `for` loop.

In Smalltalk, however, this type of operation (i.e. where you want to initialize some values and then perform the same thing on all elements in a collection) is so common that an extremely efficient construct is provided. This construct is called the `inject`: mechanism. For example, assume you have a bag of integers and real numbers which you want to sum. You can use `inject:` to do this, for example:

```
| aBag result |
aBag := Bag new.
aBag add: 12; add: 24; add: 23.56; add: 7.
result := aBag inject: 0 into: [:sum :item | sum + item ].
```

This injects the initial value zero into `sum` and `item`. It then binds `item` to each of the elements of the bag in turn. Each time it does so, it adds `item` to the current value in `sum` and saves the result into `sum`. This is therefore equivalent to writing:

```
| sum aBag |
aBag := Bag new. sum := 0.
aBag add: 12; add: 24; add: 23.56; add: 7.
aBag do: [:item | sum := sum + item].
result := sum.
```
An interesting exercise is to create a very large bag and an array (e.g. over 100,000 numbers) and time
the performance of the inject: message versus the do: message on the two objects. The result of doing
this for bags and arrays of 100, 1000, 10000, 100000 and 1,000,000 is interesting. The performance of
the array is noticeably faster, however the differences between the inject: and do: messages (for the
same class) are negligible.

The Smalltalk facility which allows the developer to time their code is `millisecondsToRun:.`
This is used to calculate the processor time taken to execute the code in the block passed to it. For
example:

```
| anArray timel aNumber |
anArray := Array new: 10000000.
1 to: 10000000 do: [:i | anArray at: i put: i].
timel := Time millisecondsToRun:
[anArray inject: 0 into: [:sum :item | sum + item]].
Transcript cr; show: 'Inject '; show: timel printString.
```

## 11.11 Conversion

An instance of one collection can be converted into a different sort of collection with certain conditions.
For example, it is possible to convert a Bag instance into a Set instance, but any duplicate objects in the
Bag instance will be removed. For example:

```
| a b |
a := Bag new.
a add: 'John'.
a add: 'Paul'.
a add: 'John'.
b := a asSet.
```

It is quite common to want to take a set or a bag and to sort it in some manner. The easiest way of doing
this is to convert it to a sorted collection. For example:

```
| aBag aSortedCollection |
aBag := Bag new.
aBag add: 'John'; add: 'Paul'; add: 'Denise'; add: 'Fiona'.
aSortedCollection := aBag asSortedCollection.
aSortedCollection do: [:item | Transcript cr; show: item].
```

This results in the list of names being printed alphabetically in the Transcript (see Figure 11.2).

<figure><img src="image_52.png" /><figcaption>Figure 11.2: Printing a sorted list in the Transcript</figcaption></figure>

You should note that these conversion messages do not affect the receiving object in anyway. That is, it does not actually convert the collection, rather it creates a new collection of the correct class and fills it with the objects in the receiving collection.

The other commonly used conversion messages include:

* `asBag`. This will return a bag collection

* `asSet`. This returns a set collection. Note if duplicates existed in the receiving collection, they will have been ignored.

* `asOrderedCollection`. This returns an `OrderedCollection` with elements from the receiver. The ordering is arbitrary.
* `asSortedCollection`. This creates a `SortedCollection`, sorted so that each element is less than or equal to (`<=`) its successors. An error will be generated if the elements within the collection do not respond to this message.

* `asSortedCollection: aSortBlock` This uses `aBlock` to sort the elements in the `SortedCollection`. The `aBlock` must take two parameters. For example

```
#( 5 1 3 7 9 2) asSortedCollection: [:x :y | x>= y]
```

will produce a sorted collection of the numbers.
# 12. An Object Oriented Organizer

## 12.1 Introduction

This chapter presents a detailed example application constructed using the collection classes. The Organizer is in tended as an electronic personal Organizer. It therefore possesses an address book, a diary (or appointments section) and a section for notes. The remainder of this chapter describes one way of implementing such an Organizer. At the end of this chapter is a programming exercise for you the reader.

## 12.2 The Organizer

This example involves more than one class and has a more complex architecture than anything you have seen so far. The architecture is illustrated in Figure 12.1. This example illustrates another important concept in object orientation, that of an object within an object. These are often referred to as *part-of* hierarchies, i.e. one object is *part-of* another. This should not be confused with the class hierarchy which is a *kind-of* hierarchy.

<figure><img src="image_53.png" /><figcaption>Figure 12.1: The structure of an *Organizer* Object</figcaption></figure>

As illustrated in Figure 12.1 an instance of the *Organizer* class contains three other objects. These objects are held in the instance variables *addressBook*, *appointments* and *notes*. The instances within *addressBook* and *appointments* are dictionary objects, while the *notes* instance variable holds a *bag object*.

## 12.3 The class definition

We shall put all *Organizer* class in a class category called *Organizer Class*. As illustrated in the above figure the class definition possesses three instance variables, *addressBook*, *appointments* and *notes*. Figure 12.2 illustrates the class definition.
<figure><img src="image_54.png" /><figcaption>Figure 12.2: The Organizer class definition</figcaption></figure>

The class comment has been defined as follows. Remember providing a class comment is a good habit to get into.

Class: Organizer Author: John Hunt Date: 27 September 1995

Purpose: This is a class definition which provides some of the facilities of a personal Organizer.

History:

27 September 1995 John Hunt New Class

Instance variables:

addressBook <aDictionary> Holds names and addresses.

Appointments <aDictionary> Holds dates and things to do.

notes <aBag> Scratch pad for notes

Usage:

To try the class out select the following and 'do it'.

| temp |

temp := Organizer new.

temp newAddress: 'Room 47' for: 'John'.

temp newAddress: 'Room 46' for: 'Patrick'.

temp newAppointment: 'Meet with MEng' for: '10/10/95'.

temp addNote: 'I must do all my work'.

temp addNote: 'Today is a brand new day'.

temp addressFor: 'John'.

temp appointmentFor: '10/10/95'.

temp printNotes.

temp inspect.

## 12.4 The initialize-release protocol

The first protocol we will define will be the "initialize -release" protocol. As usual we will define the initialize method. This method will be used to initialize each of the instance variables with appropriate objects. This is necessary for the other methods to function correctly. The `addressBook` is initialized to hold a `Dictionary` object as is the `appointments` instance variable, while the `notes` instance variable holds a `Bag`. Note however, that we do not access the instance variables directly, even though we can as we are within the same class. This is because, by using the `updater` methods we can ensure that any modification relating to how the `Organizer` class represents an `addressBook`, `appointments` or `notes` will be localized to the methods which access and update the instance variables. Otherwise, if we changed the internal representation we would have to modify every method which accessed them. This could make maintenance very difficult.

Figure 12.3 illustrates the System Browser with the `initialize` method for the `Organizer` class. Your definition should look like this.
<figure><img src="image_55.png" /><figcaption>Figure 12.3: Defining the `initialize` method in the `Organizer` class</figcaption></figure>

## 12.5 A class side method

We shall now do something we have not yet done. We shall define a class method. To do this, first select the class radio button below the class list window. You will now be on the *class side* of the `Organizer` class. You should see that the code view window has changed and now indicates the class instance definition. You will also see that your `initialize-release` protocol and `initialize` message have disappeared. This is because you are now on the *class side* and they are part of the *instance side* definitions.

We are now going to define a class message protocol. Just as before, to do this you must first define the protocol name. You do this using the right button menu in the *protocol window*. Call the new protocol "instance creation". Now define a method in the code view window called `new`. Follow the example illustrated below exactly.

```python
new
    ^super new initialize
```

Note you must make sure that you include the return symbol "^", otherwise you will get the class `Organizer` returned in response to the message `new`, rather than the new instance you wanted. The main purpose of this method is to make sure that the *instance method* `initialize` is sent to the new instance of an `Organizer`, before anything else happens. This is a common use for redefining `new`, i.e. doing something before anything else can get its hands on it. The System Full Browser (available with the advanced toolkit) is illustrated in Figure 12.4. This figure presents the state of the system after the class side method has been defined.

<figure><img src="image_56.png" /><figcaption>Figure 12.4: Defining the class side new method</figcaption></figure>
## 12.6 The private-updating protocol

Next we return to the instance side of the class (by selecting the instance radio button in the System Browser) and define each of the methods in the *private-accessing* protocol. Remember you MUST move back to the instance side of the class by selecting the *instance* radio button below the class list. Notice that the name of this protocol is comprised of two names “private” and “updating”. This is because, it is not intended for use by users of this class. Rather it is used by the initialize method to set up an instance of this class. The methods there are “private” to the object and are used for “updating” the state of the object.

The `addressBook:` method is an updater method for the `addressBook` instance variable. It is used to accept a new dictionary object to use for the `addressBook`. It is intended only for use with the instance creation method of the `Organizer` class.

```python
addressBook: aDictionary
        addressBook := aDictionary
```

The `appointments:` method is an updater method for the `appointments` instance variable. It is used to accept a new dictionary object to use for the `appointments`. It is intended only for use with the instance creation method of the `Organizer` class.

```python
appointments: aDictionary
            appointments := aDictionary.
```

Finally, the `notes:` method gives the `notes` instance variable a `Bag` to hold its contents.

```python
notes: aBag
        notes := aBag.
```

Figure 12.5 illustrates the state of the System Full Browser at the end of these steps.

<figure><img src="image_57.png" /><figcaption>Figure 12.5: The private-updating protocol</figcaption></figure>

## 12.7 The accessing protocol

Now we will define the methods for the *accessing* protocol. First define the protocol then each of the following methods in turn. We will first define the instance variable accessors and then the `Organizer` specific methods. As before, the accessor methods have the same name as the instance variables. We will also define methods which are used to set the contents of instance variables.

The `addNote:` method adds a new note to the `notes` instance variable.

```python
addNote: aNote
        notes add: aNote.
```

The `newAddress:for:` method is used to add a new address to the address book. It is illustrated in Figure 12.6.
<figure><img src="image_58.png" /><figcaption>Figure 12.6: The `newAddress:for:` method</figcaption></figure>

The method for adding a new appointment is essentially the same as the `newAddress:for:` method.

```kotlin
newAppointment: anAppointment for: aDate
  "This method is used to add a new appointment to the
   appointments dictionary."

  | alreadyThere |
  alreadyThere := appointments at: aDate ifAbsent: [].
  alreadyThere = nil
      ifTrue: [appointments at: aDate put: anAppointment]
      ifFalse: [Transcript show:
                 'An entry with key is already present']
```

The remaining accessor methods in this protocol are relatively straight forward, they are therefore
listed below with no additional commentary.

**addressBook**
"This is an accessor method for the addressBook instance variable"
^addressBook

**appointments**
"This is an accessor method for the appointments instance variable"
^appointments

**notes**
"This is an accessor method for the notes instance variable"
^notes

Now we will define the methods used to access information within the instance variables. These are
Organizer specific operations. The `addressFor:` method is used to retrieve an address from the
address book.

**addressFor:** aName
| anEntry |
anEntry := addressBook at: aName ifAbsent: [nil].
^anEntry

The `appointmentsFor:` method is used to retrieve an appointment from the `appointments` instance variable.

**appointmentFor:** aDate
| anEntry |
anEntry := appointments at: aDate ifAbsent: [nil].
^anEntry

Finally, the `printNotes` method is used to display all the notes which have been made in the
Organizer.

**printNotes**
Transcript cr.
notes
```
do:
    [:item |
        Transcript show: item printString.
        Transcript cr.]
```

Once you have defined all the methods, you are ready to use your `Organize r`. Figure 12.7 illustrates how the `Organizer` might be used. For example, I have used the `Workspace` to create a new `Organizer` and put some entries in it. Try your `Organizer` out in a similar way. Try extending it by adding additional functionality. For example, provide a way of deleting an address or replacing it with a new one.

<figure><img src="image_59.png" /><figcaption>Figure 12.7: Using the `Organizer` class in a `Workspace`</figcaption></figure>

## 12.8 The Financial Manager project

At certain points throughout the remainder of this book you will be asked to develop a small project. This project will provide the basic functionality of the Financial Manager application.

The aim of the Financial Manager application is to keep a record of deposits and withdrawals from a current account. Associated with this, it should keep an up to date balance, as well as allow statements to be printed.

You should be able to:

1. Add deposits to the account for a specified amount.

2. Make payments (withdrawals) from the account for specified accounts.

3. Get the current balance.

4. Get a statement of all payments and deposits made, in the order in which they happened. This statement should be printed to the `Transcript`.

To do this you should use a collection class to hold the statement in conjunction with a new class subclassed off the class `Object`, which will hold the current balance and handle deposits and withdrawals.

Assuming the class you define is called `FinancialManager`, then you should be able to run the following `Smalltalk`:

```
aFinancialManager |
aFinancialManager := FinancialManager new.
aFinancialManager deposit: 25.00.
aFinancialManager withdraw: 12.00.
aFinancialManager deposit: 10.00.
aFinancialManager deposit: 5.00.
aFinancialManager withdraw: 8.00.
Transcript show: 'The current balance is ',
                  FinancialManager balance printString.
Transcript cr.
aFinancialManager statement.
```
The result of evaluating this code should be:

The current balance is 20
Statement:
deposit 25.00
withdraw 12.00
deposit 10.00
deposit 5.00
withdraw 8.00
# 13. Streams and Files

## 13.1 Introduction

This chapter discusses the second most used class hierarchy in Smalltalk; the `Stream` classes. The `Stream` classes are used (amongst other things) for accessing files. The remainder of the chapter is structured in the following manner: Section two describes the `Streams` classes. Section three describes how the stream classes can be used for file access. Section four describes an example of using files and streams.

## 13.2 Streams

<figure><img src="image_60.png" /><figcaption>Figure 13.1: The structure of the `Stream` class hierarchy</figcaption></figure>

`Streams` are the second most used set of classes. `Streams` are objects which serve as sources or sinks of data. At first this concept can seem a bit strange. The easiest way to think of streams are as streams of data (as opposed to water) either flowing from a pool of data or into a pool of data.

There are a number of different types of stream in the Smalltalk system, and each can have a surprisingly wide range of uses. Figure 13.1 illustrates the structure of the stream class hierarchy. The `Stream` class is the root class of this hierarchy. Below this are stream classes for reading, writing, for accessing external files etc.

A stream may be input only (`ReadStream`), output only (`WriteStream`) or input and output (`ReadWriteStream`). They can be internal streams (i.e. that act as a source or sink for data internal to the image) or external streams (i.e. the source or sink for the data is external to the current image. A file is a typical example of an external source or sink). `Peekable streams` also have an internal record of their current position and can look ahead in the stream for information.

`Streams` have various access methods defined which allow the next item to be obtained or provided. Some of the more useful methods include:

* `next` Answer the next object in the receiver stream and advance the position indicator by one.

* `peek` Answer the next object in the receiver stream, but do not advance the position indicator.

* `nextPut`: `anObject` Write `anObject` at the current position.

* `nextPutAll`: `aCollection` Write all elements of the collection to the receiver stream.

* `atEnd` Answer true if the stream is at the end else answer false.

Others include `next`: `anInteger`, `peekFor`: `anObject` and `skipTo`: `anObject`. What operations can be performed on `Streams` depends on the class of stream being used. Figure 13.1 illustrates the structure of the stream hierarchy.

Typically `streams` are connected to files (using one of the `ExternalStream's` subclasses) or to a collection of data (using one of the `InternalStream's` subclasses). If a stream is connected to an
external device (including a file) then it essentially acts as an interface to that external device. It thus
allows messages to be sent to and received from an external device object enabling it to accomplish
various activities including input and output. If a stream is connected to a collection (such as a string) it
can act as a means for processing the contents of a collection. In both cases the stream views the source
(or sink) of the data as being able to provide (or receive) a data item on request.

13.3 ASCII files

13.3.1 Working with ASCII files

There are a wide range of file handling facilities available within Smalltalk. Most are provided by one
of the subclasses of the class Filename and Stream . The Filename class is an abstract superclass in
which the basic framework for files is defined. Most of the work of this class is actually performed by
one of its (platform specific) subclasses. It is this which is one of the facilities which allows you to
ensure that your code can run on any platform, even if you are accessing the host platform’s file system!
In the remainder of this section we shall look at some of the most common operations.

13.3.2 Creating, reading and writing a file

To create a file you must first have a filename to work with. A filename is created by sending the message asFilename to a string. This converts the string into an appropriate form for the host operating system. You now have a filename, however you need to link this file name with an actual file. To do this you use an instance of one of the streams classes (see earlier in chapter). This can be done by sending the message writeStream, readStream or readWriteStream to a filename (it is rarely a good idea to use the readWriteStream option. It is invariably better to use either the readStream or writeStream messages). In effect this links the resulting instance directly to the actual file. In the case of creating a new file, it also creates the file for you when the first character is written to it. You now have something to which you can send ASCII text.

You may wish to check to see if a file exists before attempting to open it (e.g. to be sure there is
something to read from or to make sure you don't overwrite an existing file). You can do this with the
exists message. This message returns true if the file is already present and false if it does not exist.

To close the file once it has been opened there is a close message. This message closes the
associated file as well as the data stream to that file.

Try typing the following into the Workspace and evaluating it.

| filename stream |
filename := 'temp.txt' asFilename.
(filename exists)
    ifTrue:
        [Dialog warn: 'file ', filename asString, ' already exists'.]
    ifFalse: [
        stream := filename writeStream.
        stream nextPutAll: 'Hello World'.
        stream close.].
Transcript show: filename fileSize printString.

This example creates a file called "temp.txt" in the current working directory, assuming that one
does not already exist. It then puts the string "Hello World" in that file and closes the file. It then prints
the size of the file in the system Transcript. For example, using VisualWorks 2.5 on a Windows -95 PC,
this results in the value 11 being printed in the Transcript. If the code is evaluated a second time, it
results in a dial log box (illustrated in Figure 13.2) being displayed which warns that the temp.txt file
already exists.

<figure><img src="image_61.png" /><figcaption>*Figure 13.2: A file exists dialog*</figcaption></figure>
Notice that in this example we used the message `nextPutAll:` to save the single string 'Hello World'. Remember that strings are actually collections and what this says is save the whole contents of this collection to the file.

An important point to note about files is that it may sometimes be necessary to access a file which is in a different directory to the working directory. This can be a cause of problems when porting between platforms unless care is taken. If you hard code the name of a directory structure into your system then you will need to modify the system code before it will work on a different platform. There is a way around this using the `construct:` message. This constructs a path name which is appropriate for the platform on which you are working. For example:

```json
('dcs' asFilename construct: 'jjh')
  construct: 'visual'
  construct: 'examples'.
```

Try typing the above into a Workspace and inspecting the result. The actual pathname you obtain will depend on your host operating system. For example, on a Windows -95 PC you should see the style of pathname illustrated in Figure 13.3.

<figure><img src="image_62.png" /><figcaption>Figure 13.3: Inspecting a filename on a PC</figcaption></figure>

Other messages which may be of use include:

* `directory` Return the directory containing the receiving file.

* `isDirectory` Check to see if a filename is actually a directory.

It is also possible to obtain information on the date and time a file was modified, accessed or had its status changed. To do this first use the message `dates` (this is another aspect which can differ from one Smalltalk implementation to another). This is sent to a filename, which returns a dictionary of associations. Then the key `#modified` will access the most recent modification, the key `#accessed` will return the last access date and the key `#statusChanged` will provide the date of the most recent change in the files status (or privileges). For example Figure 13.4 illustrates checking when a file was last accessed, modified and its status changed.

<figure><img src="image_63.png" /><figcaption>Figure 13.4: Accessing a files details</figcaption></figure>

The result of evaluating the code in Figure 13.4 on the `temp.txt` file created earlier might look like:

```
Last access # (June 24, 1996 11:00:00 pm) Last modified # (June 25, 1996 1:56:54 pm)
Status changed nil
```
You can also copy, move and delete files, get the contents of directories and files as well as setting file permissions and printing files all from within Smal Italk. The messages used for these functions are all fairly intuitive and readily available in the Smalltalk documentation.

### 13.3.3 Handling file IO errors

You should always wrap your file access code up in a block and use the `valueNowOrOnUnwindDo:` message to evaluate it. This is a special version of value, which will execute the block passed to it as a parameter if an exception is raised, while the block it was sent to is executing. For example, if you try and read to a file which does not exist, then an exception will be raised and your system will be left in an unstable state with streams still open. However, if you use the `valueNowOrOnUnwindDo:` message, then you can define what should happen if such an event occurs. For example, you could specify that the stream should be closed. This is a very good way of ensuring that your file accesses are handled tidily.

For example, consider the `load:` method defined below. This method accesses a file, reading each line at a time. Once all the lines in the file have been accessed it terminates.

```Smalltalk
load: filename

| newFile newLineChar stream readingBlock item student |
| newFile := filename value asFilename.
| newFile exists
| ifTrue:
|     [newLineChar := Character cr.
|     stream := newFile readStream.
|     contents := OrderedCollection new: 250.
|     readingBlock :=
|     [[stream atEnd]
|     whileFalse:
|         [item := stream upTo: newLineChar.
|         contents add: item.]]
|     Cursor read showWhile:
|         [readingBlock valueNowOrOnUnwindDo:
|             [stream close]]].
|     ifFalse: [Dialog warn: 'File does not exist!!']
```

There are three things to note about this method from a Smalltalk point of view.

* The first is that we read in one line of the file at a time by telling the (read) stream that we wanted to read up to a carriage return. To do this we send the `upTo:` message to the stream with the `newLineChar` as the parameter. You can use this to read in text up to any character in the input stream.

* If the file exists, a block is created which contains the code which will read in the data in the file. This block is assigned to a variable `readingBlock`. This block is evaluated by sending it the `valueNowOrOnUnwindDo:` message. Notice that if anything happens to raise an error during these operations (e.g. the file system becomes full), the block passed as a parameter to the `valueNowOrOnUnwindDo:` message will be executed. In this case, it will close the stream (i.e. it will close the file). Thus, if anything goes wrong during the processing of the file, the file will be closed and the system left in a stable state. Indeed when the last statement has been executed in the write block, the block passed as a parameter will be executed. Thus the stream will also be closed. This is a very good way of handling the process of closing the link to files.

* The other point is that the whole of the read expression (i.e. `readingBlock valueNowOrOnUnwindDo: [stream close]`) is passed in a block to the `showWhile:` message. This message is part of the cursor protocol and is used to specify the type of cursor to be displayed while a particular operation is being performed. In this case, the `read cursor` will be displayed while the text file is being read in. This provides some visual feedback to the user.

## 13.4 The Binary Object Streaming Service

The Binary Object Streaming Service (or BOSS for short) is a very useful and effective way of storing information in the form of objects (instances). If you were to save information to an ordinary text file, then all you could save would be the ASCII version of the data held by the object. You would then need
to reconstruct the data into objects when you read the text file. This would mean that you would have to invent some way of indicating that certain data was associated with certain objects and that certain objects were related (if you were dealing with a composite object). All of this would be very time consuming and error prone. It would also be very unlikely that the ASCII data written out by someone else would be in the right format for your system.

The BOSS is provided by VisualWorks as a way around this. It allows objects to be directly stored to a file in a compact and encoded form. You do not need to convert the objects into anything special nor do you need to worry about reconstructing the objects when you load them back in. In addition everyone else who uses the BOSS will be able to read and write to your BOSS files. The action of writing objects to a BOSS file is referred to by Smalltalkers as BOSSing out (or in) the objects.

### 13.4.1 Saving to BOSS

It is possible to "BOSS out" a single object, a series of objects or a whole collection of objects. It is also possible to BOSS out a composite object. If an object references another object, then both the original object and the objects which it contains are saved to the BOSS file. The BOSS file is an incremental file so it is possible to add objects to a BOSS file at different times (i.e. in different executions of the same image). It is also possible to read the BOSS file one object at a time (assuming the objects were written incrementally). This means that you do not have to read the whole file to access the third object etc.

The procedure for creating a BOSS file is relatively straight forward and is outlined below:

1. Create a data stream to write the objects to. This is usually a write stream onto a specified filename.

2. Create the BinaryObjectStorage system (BOSS) object. This is done using the instance creation method `onNew:` with the data stream as the parameter.

3. Using the `nextPut:` message save each object to the BOSS object. Each object you wish to save is passed as the parameter of the `nextPut:` message.

4. Once you have finished BOSSing out the object you can close it by sending it the message `close`.

If you want to save a whole collection of objects to the BOSS file you can do so by using the `nextPutAll:` message (instead of the `nextPut:` message). Each object will be stored separately, which allows each object to be retrieved separately at a later date.

If you wish to append an object to an existing BOSS file then you create a read-append data stream (rather than a write data stream), then create the BOSS file using the `onOld:` message (rather than the `onNew:` message). Finally, you need to move the file pointer to the end of the BOSS file. You can do that by sending the `setToEnd` message to the BOSS object.

A simple example of creating and saving to a BOSS file is presented below. The `bosFileName` is set to a string representing an appropriate file on the host computer system.

```java
valuesaNี้Stream := bosFileName asFilename writeStream.
bosaNี้Stream := BinaryObjectStorage onNew: valuesaNี้Stream.
bosStream nextPutAll: aList.
valuesaNี้Stream close.
```

This example saves all the elements in the variable `aList` to the `bosFile` indicated by the `bosFileName`. It then closes the file.

A point to note is that it can be a good idea to wrap the writing of objects to the BOSS file with a `valueNowOrOnUnwindDo:` message. This message is used to ensure that the BOSS file you are writing to is closed safely even if an abnormal interruption occurs. That is, the file will be closed and freed up in an appropriate manner. The message is sent to a block in which you define the write expression. It takes a second block as its argument, which executes if there is a problem or when the first block terminates. For example, we could have written the `write` part of the above as:

```java
[bosaNี้Stream nextPutAll: aList] valueNowOrOnUnwindDo:
    [valuesaNี้Stream close].
```
### 13.4.2 Reading from BOSS

You can either load the whole contents of a BOSS file, read individual objects from a BOSS file (or if you know the position of the object you are interested in) access a single object from any position in the file. This last technique is much faster than reading *n* - 1 objects to get to the *n*th object, but it does assume that you know that the object you are interested in is the *n*th object.

The procedure to follow is presented below.

1. First create a data stream to be used to read the BOSS file. This is typically achieved by send a `readStream` message to a file name which represents the name of the BOSS file.

2. Now create a BOSS object by sending an `onOld`: creation message with the newly created data stream as the parameter. You can optimize this process if you know that you are not going to write to the BOSS file. To do this you can use the `onOldNoScan`: message (rather than the `onOld`: message).

3. Obtain the objects in the BOSS file using the appropriate access message (e.g. `contents` or `next`).

4. Once you have finished reading from the boss file you should close it.

The `next` message listed in item 3 above will return a single object which can then be saved into an appropriate collection / data structure etc. The `contents` message will return an array of objects which can then be manipulated in the same way as any other array of objects. For example:

```
valuesFinancialStream bosFinancialStream
valuesFinancialStream := bosFileName asFilename readStream.
bosFinancialStream := BinaryObjectStorage onNew: valuesFinancialStream.
aBag := Bag new.
[[bosFinancialStream atEnd]whileFalse: [aBag add: bosFinancialStream next]]
valueNowOrOnUnwindDo: [valuesFinancialStream close].
```

This example illustrates two things, first it illustrates the equivalent of a while not end of file (EOF) style construct for BOSS files. This construct is the `atEnd` message. This message is used to test whether the end of the BOSS file has been reached. It is therefore possible to use it in a while loop which says "read while not end of file". The other thing this illustrates is the practical use of a `whileFalse`: loop. Many other languages would force a construct such as not (filename EOF) onto the programmer. The `whileFalse`: construct is far more elegant.

Finally, the `position`: message is used to position the BOSS file pointer so that a single object can be read from a specific point in the BOSS file. However, a record must have been maintained of what the position is (note the third object stored is unlikely to have been stored at position 3). This message could be used to create a file based version of a collection class. We shall look at this in more detail in the next section and so will leave a detailed discussion of this message until then.

### 13.4.3 Warnings about BOSS files

You should only use BOSS files to store data objects and never for interface objects. This is because the objects you BOSS out will lose their reference to onscreen objects. You should also avoid `BOSSing` out any objects associated with the execution machinery of VisualWorks. Finally, you should take care never to BOSS out a circular references as this can confuse the BOSS system.

## 13.5 Using files with the Financial Manager

This application builds on that carried out in the last chapter. The aim of that `FinancialManager` application was to keep a record of deposits and withdrawals from a current account. Associated with this, it kept an up to date balance as well as allowing statements to be printed.

A problem with that version of the application was that there was no way of permanently storing the account information. As soon as the `FinancialManager` object was destroyed (or reference to it lost) then all the information associated with it was also lost.

The aim of this exercise is to extend the existing application by adding the following features:
1. The ability to save the current statement to a file.

2. The ability to load an existing statement from a file.

This means that you should provide two new interfaces to your application, one to load a file and one to save a file. These files will contain a formatted version of the information held in the statement. The format of the text file might be: `<type of action> <amount> newline`. For example:

```
deposit 24.00
deepdraw 13.00
```

Note you should try to use a `BOSS` file as this will make accessing the contents of the file much easier. Other points to note include:

* Check to see that the file exists before loading it.

* Define a `save:` method which will save the current statement to the specified file.

* Define a `load:` method which will load a statement into the statement collection.

If you are successful then you should be able to evaluate the following in a Workspace and get the same result from both `FinancialManager` objects.

```
| aFinancialManager anotherFinancialManager|
aFinancialManager := FinancialManager new.
aFinancialManager deposit: 25.00.
aFinancialManager withdraw: 12.00.
aFinancialManager withdraw: 8.00.
Transcript show: 'The current balance is ',
                  aFinancialManager balance printString.
Transcript cr.
aFinancialManager statement.
aFinancialManager save: 'account1'.
```

```
anotherFinancialManager := FinancialManager new.
anotherFinancialManager load: 'account1'.
Transcript show: 'The current balance is ',
                  anotherFinancialManager balance printString.
Transcript cr.
anotherFinancialManager statement.
```

## 13.6 Summary

In this chapter you have encountered streams and their use in file input and output. Many simple Smalltalk applications never need to worry about file access, however, if you are ever going to do something where information needs to be stored or shared between images, then you are going to need to interact with the host file system. You have now seen the basic facilities available, the Binary Object Streaming Service (BOSS) approach to storing and accessing information in files is particularly useful. You should now spend some time exploring the stream and file facilities available in your Smalltalk system.
# 14. The Magnitude Class Hierarchy

## 14.1 Introduction

This chapter considers the magnitude class and those classes which inherit from it. This includes the `Number` hierarchy. We also consider the classes `Character`, `Time`, and `Date`.

## 14.2 The class Magnitude

The `Magnitude` class is the abstract super class of all classes which possess some concept of a size and the comparison of objects of different size (see Figure 14.1). This means that all types of numbers inherit (eventually) from `Magnitude`, although they are in fact all subclasses of another class `Number`, which acts as the abstract superclass for all numbers. This abstract class inh erits all of its size related behavior from the `Magnitude` class. Other classes which have some concept of size and thus can be compared via logical operators such as `<`, `=`, and `>` include `Time`, `Date` and `Character`. The subclasses of `Magnitude` will be considere d later in this chapter, in this section we will concentrate on the `Magnitude` class.

<figure><img src="image_64.png" /><figcaption>Figure 14.1: The top of the Magnitude class hierarchy</figcaption></figure>

The `Magnitude` class provides protocol for comparing objects whic h possess size and which can use their size to rank themselves. The relationship of this size to their peers is class dependent and is not defined by the `Magnitude` class. The comparing protocol in `Magnitude` defines the methods `<` and `=`:

* `<`. The intention i s that this method will determine if the receiver is less than the argument object. This method is a subclass responsibility. It is used by numerous other methods and is defined here to indicate which methods should be redefined by subclasses.

* `=`. This meth od is another subclass responsibility. It is intended to determine equality between the receiver and the argument object.

Other comparison methods defined include; `<=`, `> ` and `>=` all of which are defined in terms of `<` and `=`. The protocol also defines `max:` and `min:` messages used to return either the maximum or minimum of two numbers respectively. For example:

10 max: 15.

10 min: 15.

The first expression returns the result 15 and the second 10. Magnitude also provides a test method which checks to see if a value is between two other values. For example:

10 between: 1 and: 9.
## 14.3 The class Date

Class `Date`, a subclass of `Magnitude`, represents a particular day, in a particular month of a particular year. A `date` object can be created in a number of ways. For example, it is possible to request the date today and thus create a `date` object:

```
todaysDate := Date today.
```

It is also possible to create a `date` object for an explicit `date`, using the `newDay:month:year:`. For example:

```
birthDate := Date newDay: 23 month: #Sep year: 1964.
```

Note that only the first three letters of the month name are significant and that if the century is not provided in the `year` parameter (e.g. if 64 had been passed in rather than 1964), then the current century is used as a default.

The `Date` class also allows `date` objects to be compared, added, subtracted etc. by virtue of its inherited abilities from `Magnitude`. For example:

```
(todaysDate < birthDate) ifTrue: [Transcript show: 'Weird!'].
Transcript show: (todaysDate subtractDate: birthDate) printString.
```

This will calculate the difference between today's date and the 23rd of September 1964. The result will be printed in terms of the difference in days. To convert this into (an approximate) number of years, you can divide by 365. This ignores leap years. For example:

```
Transcript show: ((todaysDate subtractDate: birthDate) // 365).
```

**Question:** Why have I used `//` rather than `/`? Answer, because `/` will return a fraction if the number of days cannot be divided exactly by 365, where as `//` will ignore any remainder.

There are also a range of other messages which are supported by the `class Date`. These messages allow you to determine if the `date` object is in a leap year, which day of the year it is, which month the `date` object is in, which year it is part of etc. Some examples using `todaysDate` are presented below:

```
todaysDate day.
todaysDate leap.
todaysDate monthName.
todaysDate weekday.
todaysDate year.
```

Class `Date` also supports a range of messages itself. These messages provide additional behavior related to dates. For example, the `Date` class will respond to messages requesting the number of days in a particular month for a particular year:

```
Date daysInMonth: #Feb forYear: 1997.
```

Another class method can be used to determine if a given year is a 1 leap year or not. This is done using the `leapYear:` message to the `Date` class:

```
Date leapYear: 1999.
```

## 14.4 The class Time

The class `Time`, provides a similar set of features for objects which represent a specific instant of time (to a particular second) as the class `Date` does for a specific calendar date. A new instance of the class `Time` can be created using the instance creation message `now` or by reading from a string. The string can contain hours, minutes and seconds separated by colons (`'11:59:20'`). It can also contain an AM or PM designation. For example:

```
currentTime := Time now.
previousTime := Time readFromString: '1:10:20 am'.
```
Just as with the class `Date`, these times can be compared, added and subtracted. For example:

```perl
(currentTime = previousTime) if True:
    [Transcript show: 'Time has stood still!'].
differentTime := currentTime subtractTime previousTime.
```

However, the usefulness of the `subtractTime:` message is somewhat limited. For example, having evaluated this expression I obtained the result `2:57:18 PM`, when what I really wanted to know was the difference in hours. In the case of time, I can obtain this by converting the time into seconds and dividing by 3600 (the number of seconds in an hour). For example:

```perl
| currentTime previousTime differentTime |
currentTime := Time now.
previousTime := Time readFromString: '1:00:20 am'.
differentTime := currentTime asSeconds - previousTime asSeconds.
differentTime // 3600.
```

There are two class side messages which may be of general use. The `millisecondClockValue`. This message returns a value indicating the number of milliseconds since the system clock was reset. It can be useful as a means for generating an unique name for a temporary file etc. The uniqueness of such a filename can not be guaranteed as there is a vague chance that a file with the same name may have been left around from an execution of the system prior to the resetting of the system clock (although the chances of a temporary file being created with a name derived from the same millisecond clock reading are remote). For example:

```
Time millisecondClockValue.
```

The second class side message is the `millisecondsToRun:` message. This takes a block as a parameter and generates a report on the time required to evaluate that block. This message is most often used when determining the performance of various constructs. For example, in the last chapter it was used to compare the `do:` loop with the `inject:` construct on two collection classes `Bag` and `Array`. For example:

```perl
Time millisecondsToRun:
    [1 to: 10000 do: [:i | Transcript show: ' ', i ]].
```

On a Pentium 120 PC with 16 megabytes of memory this resulted in a value of `79056` seconds being returned.

## 14.5 The class Character

Characters such as letters (e.g. A, b or Z) are objects in the `ir own right in Smalltalk`. When they are written alone they are preceded by a dollar sign. For example:

```
$A, $b, $Z
```

These objects can be combined together to form strings (which are actually collections of characters).

As the `Character` class inherits from `Magnitude`, you can compare characters to determine if one is greater, less than or equal to another. For example:

```
Transcript show: ($A < $a) printString.
```

In addition, `Character` adds another comparison method called `sameAs:`. This method ignores case. Thus it is possible to evaluate the following and have true printed in the Transcript:

```
Transcript show: ($A sameAs: $a) printString.
```

The `Character` class also understands the differences between alphabetic characters, numeric characters, vowels, uppercase and lowercase letters etc. These are provided by methods in the testing protocol, which include:
aCharacter isAlphabetic.

aCharacter isDigit.

aCharacter isLetter.

aCharacter isLowercase.

aCharacter isVowel.

It also provides some useful conversion methods, including:

aCharacter asUppercase.

aCharacter asLowercase.

aCharacter asInteger.

The first two messages would convert the contents of aCharacter either to an uppercase character or a lowercase character while the third message would return the ASCII code a letter or number.

Just like the classes Date and Time, the Character class provides some useful class side protocol. The methods provided on the class side provide access to non-alphanumeric characters. These can be extremely useful when processing text (as was illustrated in the example presented earlier in the book). The facilities available allow you to obtain the character for carriage return, backspace, space, new page and tab (amongst others). For example:

newlineChar := Character cr.

spaceChar := Character space.

tabChar := Character tab.

## 14.6 Further reading

The Object Reference manual supplied with your Smalltalk system will provide a detailed description of all the classes described in this chapter. For a detailed description of the Number hierarchy see [Hopkins and Horan 1995].
# 15. Some More Tools of the Trade

## 15.1 Introduction

In this chapter you are introduced to the use of *breakpoints* and user initiated *exceptions*. Breakpoints in particular are extremely useful and you will find that you will make extensive use of them, not just for debugging but also to help you understand how objects are behaving. The use of the *file in* and *file out* facilities for saving classes onto your host file system are also discussed. These are important as without this ability you would lose any source code you developed when you started a new image. Finally the use of the *changes* file and *projects* are discussed.

## 15.2 Errors and breakpoints

As in most languages, it is possible to generate user specified errors (sometimes known as mishaps or exceptions in other languages). This is achieved by sending the message `error` to an object. Errors are usually intended to force the user of the system (which may be another developer) to stop executing and investigate the problem. A similar operation is provided by the `halt` message. The only real difference is that the `halt` message is intended as a debugging aid, while the `error` message is intended for use in undesired situations.

### 15.2.1 Programmer generated errors

Programmer generated errors are really exceptions, which are not handled by the system. These exceptions are generated by the message `error`. For example:

```
self error
```

This message would result in an exception log being displayed. These dialogs allow the user a number of options, however, you should notice that the "proceed" option is grayed out. This is because proceeding is not an option if an error has been encountered.

If you wish, you can use a version of the error message which will take a string as a parameter. This string is displayed to the user and can act to provide further information about the error. For example:

```
self error: 'This is not allowed!'.
```

Note that an error message is a message just like any other. You can therefore use it anywhere that you would use a message expression, this means for example that you can conditionalize the call to error:

```
(x < 0)          ifTrue: [self error: 'Divide by zero coming'].
z := y / x.
```

Have a look at the `add:` method defined within the `Array` class of objects for an example of an error handling method. You can do this by selecting the `find class` option off the right mouse button (middle on a three button mouse) in a browser.

### 15.2.2 Breakpoints

*Breakpoints* are often useful in determining what is really happening inside the system. In Smalltalk, breakpoints simply provide a controlled mechanism for entering the debugger at a known point in the execution.
Breakpoints may be placed in a method by using the `halt` breakpoint method. This can be used with or without arguments. For example:

```
self halt. or self halt: 'An example breakpoint'.
```

This form of the halt message is useful if more than one breakpoint exists within the system as it allows the breakpoint to be identified. For example, the result of executing the above halt message expression is illustrated in Figure 15.1. Notice that, the dialog is actually entitled "Exception ". This is because both error messages and halts raise a signal which is caught by the exception handler. Notice, that unlike the result of encountering an error message, the user can proceed after evaluating a halt message.

<figure><img src="image_65.png" /><figcaption>Figure 15.1: An example breakpoint dialog</figcaption></figure>

When a halt expression is encountered, the message halt is sent to the receiver. The corresponding method is implemented in `Object` so all objects respond to it. This opens the halt notifier from which point you can proceed as if the halt had never been encountered, terminate or select the debug option if you wish to analyze the state of the object when the breakpoint was encountered. If the `debug` option is selected then a debugger window is opened on the method currently executing.

Note that just like an error message, a halt message can be used anywhere that you would use any other message expression. You can therefore conditionalize the call to halt:

```
(x < y) ifFalse: [self halt].
```

# 15.3 File in/file outs

## 15.3.1 File out

It is possible to file out any group of definitions using the System Browser (or one of its derivatives). That is, you can save to a file whole class categories, individual classes, whole method protocols or just individual methods. By doing so you create a file on the host system's file system, which contains a plain ASCII definition of the appropriate class, method etc. To save information to file, select the **file out** option in the appropriate browser window.

This ASCII file can be viewed in the same way as any other ASCII file using one of the host system's editors / viewers (e.g. EMACS, vi or more on a UNIX system). However, if you do this, you will notice that some additional characters have been added (these are "!" and used as delimiters) as well as extra statements indicating that something is a class comment or a method protocol name etc. Normally, you would not need to edit this file and indeed, unless you are sure of what you are doing, you should not do so.

The purpose of creating "file outs" can be to provide a permanent storage for your class definitions etc. or to share those definitions with others. If you have created a definition which is particularly important and which you do not want to lose at any cost, it is often a good idea to file it. At least then, if you have a catastrophic failure and have to create a whole new image on a new platform, you can still reconstruct your important work.

Another reason for creating file outs, is that they take up a lot less space than the system image. Therefore, if you have a number of sets of definitions which you wish to retain, but not enough space to
maintain a large number of images, then you can create file outs which will allow you to construct the images you require, when you require them.

You can file out a whole class category, a class, a message protocol or a single method. This is done by selecting " **file out** " from the right mouse button menu (middle mouse button on a three button mouse) in the appropriate window from the System Browser (or one of the other available browsers, e.g. the excellent Full Browser).

### 15.3.2 File in

<figure><img src="image_66.png" /><figcaption>Figure 15.2: The File List tool</figcaption></figure>

If at a later stage you wish to "file in" a "file out" file, you can do so using the file tool. This tool is accessible from the VisualWorks Launcher by clicking on the filing cabinet icon. This presents the user with a (very) basic file editor.

To view files, type into the top pane of the file editor the appropriate path (if required) for your host system, followed by either a specific name or a wild card.

The list of files will be displayed in the middle pane of the file tool. If you select any of these files, their contents will be displayed in the bottom window. If the files are very large the system will ask you whether you really want to see their contents or whether just information on the file (such as its size) will do. You would use the right (or middle) mouse button to file in one of the files. If you do file it in, then a trace of what is being loaded (and compiled) will be printed in the system Transcript window. Once the load is completed, if it is successful you will be able to view it using the System Browser. Note that if you have loaded in a whole class category, you will not be able to view it until you select update in the category pane of any open browsers, or you open a new browser. Figure 15.2 illustrates the file list tool being used to examine the contents of a file called Example.st. This file contains the source of a simple example class.

If a file is selected and displayed in the bottom window, then you can edit that file and save the changes you have made. You can also select part (or all) of the file and then use the "do it" or "print it" options to execute that selected code. This can be a very useful feature.

Note that you can also file in source code under programmatic control. To do this you need to send the message `fileIn` to a file. For example:

```
'example.st' asFilename fileIn.
```
If the file does not exist you will raise an exception "File not found". Otherwise the result of filing in the file will be printed in the System Transcript window.

## 15.4 Change list

### 15.4.1 The changes file

To understand the use of the changes list tool, you must first understand the significance of the changes file. This is a system provided file which has a `.cha` extension (and is named after the image, for example, if the image is named `Visual.im` then the changes file will be named `Visual.cha`). The changes file is always located in the same directory (folder) as the image file (and should never be manually moved).

This file lists all the changes which have been made to VisualWorks for the current image. That is, all the changes to existing classes and methods as well as all new classes and methods which have been defined. It also records all the actions that have created objects and sent messages in the image. Thus as you develop a system within an image, your changes file grows - each time you make a change it is recorded.

In fact, if you manually move your changes file and then attempt to view the code you have written you will find that VisualWorks says that it can't find the changes file and will have to disassemble your code. This is an indication that VisualWorks uses the changes file to store the actual source of the compiled byte encoded class and method definitions.

The main use of the changes file, however, is as a recovery aid. It allows a sequence of changes to be replayed. This may be done following a system crash, or following the accidental deletion of a class or method. The result is that, even if you did not save your work before a system crash, you can get back to where you were by replaying the changes file. This is done using the Change List tool.

### 15.4.2 Viewing and replaying the changes file

The Change List tool (illustrated in Figure 15.3) is used to view the contents of the changes file. It is made up of:

* a scrollable list selection (referred to as the changes view),

* a set of selection boxes which allow the user to restrict the display of past changes (for example in Figure 15.3 the list has been restricted to references to the same class, in this case the `MyClass` class).

* a code display area where the result of the change (if any) is displayed. In Figure 15.3 the result of editing the `age` method is presented.
<figure><img src="image_67.png" /><figcaption>Figure 15.3: The Change List tool</figcaption></figure>

The changes presented in the *changes view* often need to be filtered before being re-run. For example, if the list of changes includes the creation of windows or test objects, you probably don't need to redo those commands. If the system crashed in response to a message sent, you probably don't want to resend that message etc.

Once you have got a list of changes which reflect the set of operations you want to perform you can replay them using one of the replay options from the right mouse button (middle on a three button mouse) menu.

# 15.5 Working with projects

## 15.5.1 Projects - what are they?

A project is a way of organizing your development environment. It allows the developer to manage a number of different tasks at the same time within the *same image*. The way to think about this is that if what you see on the screen can be viewed as the VisualWorks desktop, then projects allow you to have multiple desktops for different parts of your work.

Why is this feature useful? Well consider that you are trying to draw a diagram on a flip chart. Then you might see a blank page with a number of pens clipped to the side of it. This would be fine for some diagrams, however, if you need to draw a number of associated diagrams, then you would either need to get a larger flip chart, or you would have to use more pages. Projects allow you to use multiple pages, each page having its own VisualLauncher. When you switch between projects, the layout of the screen will be restored to the state of the screen when you last left that project. If the project has just been created, then you will see only the visual Launcher.

## 15.5.2 Creating a new project

By default, when you start the VisualWorks image you are in the root project. To create a new project you select the **Open Project** option off the changes menu on the VisualLauncher. In response to this, the system displays the window illustrated in Figure 15.4. This allows you to provide some notes about the project in a scrollable text window (for example, what the project is about, things to do etc.). This is a good idea as it acts as a project documentation tool. It is also a good idea to change the window label to something which indicates the purpose of the project. This can be done using the right mouse button (on a three button mouse). This displays a menu with a **relabel as ..** option.
<figure><img src="image_68.png" /><figcaption>Figure 15.4: Creating a project</figcaption></figure>

To enter the project select the **enter** button on the window. To exit a project select the **Exit project** option from the VisualLauncher from within the project. Exiting the project in this way will bring you back up a level and your desktop will be restored to the state it was in when you entered the project. You can delete a project by closing the project window. For example, if I wished to destroy the project in Figure 15.4, then I would close that window using the Windows-95 close icon.

<figure><img src="image_69.png" /><figcaption>Figure 15.5: Project hierarchy</figcaption></figure>

Projects can be nested hierarchically to any depth (although it is rarely useful to go beyond 2 or 3 levels). This means that the project structure illustrated in Figure 15.5 can easily be constructed. In this structure, at the top level the developer sees the *User Interface* project, the *Data Management* project and the *Operations* project. When the user enters the *Data Management* project, then they see the *Database Interface* project and the *Sensor Interface* project.

This means that, when they are working on the user interface project, they do not see the windows they have been using in any of the other projects. They can thus leave one of the other projects in a particular state and come back to it later.

### 15.5.3 Changes and projects

In addition to the changes file created for the whole image, a project has its own *changes set*. This changes set is a summary of the changes which have been made to that project. This means that, unlike the changes file, it does not include all changes to the system. Instead it lists those classes which have been modified within the current project.

The changes set of a project can be accessed using the **Inspect ChangeSet** option from the changes menu on the VisualLauncher. If you wish to save the changes made to a project, you can do it using the **file out as ..** option from the right mouse button menu (middle on a three button mouse) available from the left hand window of this inspector. This can be a useful way of exchanging changes with other developers.

### 15.5.4 Warnings about projects

There are two points you should note about projects. The first is that they are only a visual aid to project organization. That is, all the source code changes you make are global to the current image. Many developers when they first encounter projects assume that changes in one project will be limited to that project. They aren't and this can be rather counter intuitive. Care should therefore be taken when modifying classes in one project which may be used in another project. Secondly, as all changes are actually made to the whole image, it is a mistake to assume that when a project is deleted, its affects will also be deleted.
15.6 Summary

In this chapter you have encountered a number of tools which you are likely to make a great deal of use of. At this point you should try some of them out and get familiar with what they do. None of the tools is that complicated and once you understand what they do and why, they can prove to be extremely useful and make your life a lot easier.
Part Three

**Object Oriented Design**
# 16. Object Oriented Analysis and Design

## 16.1 Introduction

This chapter provides an introduction to Object Oriented Analysis and Design. It will survey the most significant methods to emerge since the late 1980's. This means that we will concentrate primarily on OOA [Coad and Yourdon 1991], Booch [B ooch 1991, 1994], OMT [Rumbaugh et al 1991], Objectory [Jacobson 1992] and Fusion [Coleman et al 1994]. We will also introduce the Unified Modeling Language (or UML) [Booch et al 1996; Booch and Rumbaugh 1995].

The aim in this chapter is not to be comprehensive either with regard to the range of methods available, nor with the fine details of each approach. Rather it is to provide an overview of the design process, strengths and weaknesses of some of the important and reasonably representative methods.

In the remainder of this chapter we briefly introduce the Unified Modeling Language, Object Oriented Design (OOD) and then summarize a number of OOD methods.

## 16.2 The Unified Modeling Language

The Unified Modeling Language (or UML as it is known) is an attempt by Grady Booch, Ivar Jacobson and James Rumbaugh to build on the experiences of the Booch, OMT and Objectory methods [Booch et al 1996; Booch and Rumbaugh 1995]. Their aim is to produce a single, common, and widely usable modeling language for these methods and, working with other methodologists, for other methods as well. This means that the UML focuses on a standard language and not a standard process. This reflects what actually happens in reality: a particular notation is adopted as the means of communication on a specific project and between projects. However, between projects (and sometimes within projects) different design methods are adopted as appropriate. For example, a design method is intended for the domain of real-time avionics systems may or may not be suitable for designing a small payroll system. The result is that the UML is an attempt to develop a common metamodel (which unifies semantics) from which a common notation can be built. We will discuss the UML in greater detail in a later chapter.

## 16.3 Object oriented design methods

The object oriented design methods (OOD methods) we shall be considering are all architecture-driven, incremental and iterative. That is, they do not adopt the more traditional waterfall software development model adopting instead an approach which is more akin to the spiral model of Boehm [Boehm 1988]. This reflects developers' experiences when creating object oriented systems - the object oriented development process is more incremental than that for procedural systems with far less distinct barriers between analysis, design and implementation. Indeed some organizations take this process to the extreme and have adopted an *Evolutionary Development* approach. That is a system which is developed around the concept of evolutionary delivery. This means that system functions are delivered to users in very small steps with project plans being revised in light of experience and user feedback. This has proved to be very successful for those organizations who have fully embraced this philosophy and has led to much earlier business benefits and successful end-products from large development projects.
## 16.4 Object Oriented Analysis

We shall first consider the Object Oriented Analysis Approach (known as OOA) of Coad and Yourdon [Coad and Yourdon 1991]. This is because the identification of objects and classes is a crucial task in OO analysis and design, however, many techniques ignore this issue. For example, both the Booch method and OMT do not deal with this issue at all. They indicate that it is a highly creative process which can be based on the identification of nouns and verbs in an informal verbal description of the problem domain! A different approach is to use a method such as OOA as the first part of the design process and then to use some other OOD method for the later parts of the process.

OOA is aimed at helping designers identify the requirements of their software in detail - rather than how the software should be structured or implemented. It therefore aims to describe the existing system, how it operates and how the software system should interact with it. One of the claims of OOA is that it helps the designer to package the requirements of the system in an appropriate manner (for object oriented systems?) and helps to reduce the risk of the software failing to meet the customer's requirements. In effect, OOA helps to build the Object (systems) Model which we will look at in more detail when we look at OMT.

There are five activities within OOA. These act as the framework used to direct the analyst during the analysis process. They are:

1. Finding classes and objects. This activity aims to identify the objects (and the classes of objects) in the domain.

2. Identifying structures (amongst those classes and objects). Here structures relate to relationships such as *is a* as well as *part of*.

3. Identifying subjects. In essence subjects indicate related objects.

4. Defining attributes. These are the data elements of the objects.

5. Defining services. These are the active parts of objects and indicate what the object does.

These are not five steps (as steps implies a sequential ordering to the activities). Instead, as information becomes available, the analyst performs the appropriate activity. The intention is that the analyst can work in whatever way the domain expert finds easiest for them to express their knowledge. Thus the analyst may drop down deeper into one activity than the others as the domain expert provides greater information on that area. Equally, the analyst may jump around between activities identifying classes one minute and services the next.

## 16.5 The Booch method

The Booch method (also known as just Booch and Object Oriented Development or confusingly OOD) is one of the earliest recognizable object oriented design methods. It was first described in a paper published in 1986 [Booch 1986] but has become widely adopted since the publication of the book describing the method [Booch 1991] and the more recent second edition [Booch 1994].

The Booch method provides a step by step guide to the design of an object oriented system. Although Booch's books do discuss the analysis phase, they do so in too little detail, compared to the design phase.

### 16.5.1 The steps in the Booch method

The major steps in the Booch method are the identification of objects and their classes, identification of the semantics of classes and objects, identification of the relationships between classes and objects and the implementation of the classes and objects. Each of these steps is briefly outlined below:

**Identification of classes and objects.** This involves analyzing the problem domain and the system requirements to identify the set of classes required. This is not trivial and relies on a suitable requirements analysis.

**Identification of the semantics of classes and objects.** This step involves identifying the services offered by an object as well as those required of an object. A service is essentially a function performed by an object (it is therefore during this step that the overall system functionality is
devolved amongst the objects). This is another non-trivial step and may result in modifications to the classes and objects identified in the last step.

**Identification of the relationships between classes and objects**. This step involves identifying links between objects as well as inheritance between classes. As this step may identify new services required of objects, there is usually an iteration between this step and the last step.

**Implementation of classes and objects.** This step attempts to consider how the classes and objects will be implemented, how attributes will be defined and services provided. This will involve consideration of algorithms etc. This process may lead to modifications in the deliverables of all of the above steps and may force the designer to return to some or all of the above steps.

During these steps class diagrams, object diagrams, module diagrams, process diagrams, state transition diagrams and timing diagrams are produced. The class diagrams illustrate the classes in the system and their relationships. The object diagrams illustrate the actual objects in the system and their relationships. Module diagrams, in turn, package the classes and objects into modules (these modules illustrate the influence Ada had on the development of the Booch method [Booch 1987].) Process diagrams perform a similar function for processes and processors. The state transition diagrams, together with the timing diagrams, describe the dynamic behavior of the system (while the class, object and other diagrams describe the static structure of the system).

It is notable that Booch recommends an incremental and iterative development of a system through the refinement of different yet consistent logical and physical views of that system.

### 16.5.2 Strengths and weaknesses

The biggest problem for a designer approaching the Booch method for the first time is that the plethora of different notations are supported by a very poorly defined and loose process (although the revision to the method described in [Booch 1994] addresses this to some extent). It lacks the step by step guidance required. In particular it possesses very few mechanisms for determining the system's requirements. Thus its main strengths are its (mainly graphical) notations which cover most aspects of the design of an object oriented system, whilst its greatest weakness is the lack of sufficient guidance in the generation of these diagrams.

## 16.6 The Object Modeling Technique

The Object Modeling Technique [Rumbaugh *et al* 1991] is an OOD method which aims to construct a series of models which refine the system design, such that the final model is suitable for implementation. The actual design process is divided into 3 phases:

* the *Analysis Phase* which attempts to model the problem domain;

* the *Design Phase* which structures the results of the analysis phase in an appropriate manner;

* the *Implementation Phase* which takes into account target language constructs.

Each of these will be briefly described below.

### 16.6.1 The Analysis phase

Three types of model are produced by the Analysis phase; these are the object model, the dynamic model and the functional model.

The *Object Model* describes the objects in the domain, their class and the relationships between the objects. For example, the object model might represent the fact that a department object possesses a single manager (object) but many employees (objects). The object model therefore represents the static structure of the domain. The actual notation used is based on an extension of the basic Entity-Relationship (E-R) notation.

The *Dynamic Model* expresses what happens in the domain, when it occurs and what the effect is. That is, the dynamic model expresses the behavior of the system (although it does not represent how the behavior is achieved). The formalism used to express the dynamic model is based on a variation of finite state machines called statecharts. These were developed by Harel [Harel *et al* 1987, Harel 1988]
for representing dynamic behavior in real-time avionic control systems. Essentially statecharts indicate
the states of the system, the transitions between states, their sequence and the events which cause the
state change.

The *Functional Model* describes how system functions are performed. To do this it uses data flow diagrams (DFD). These illustrate the sources and sinks of data as well as the data being exchanged. They contain no sequencing information or control structures.

The relationships between these three models is important as each model adds to the designer's understanding of the domain. Essentially the relationships are:

* The object model defines the objects which hold the state variables referenced in the dynamic model and are the sources and sinks referenced in the functional model.

* The dynamic model indicates when the behavior in the functional model occurs and what triggered it.

* The functional model explains why an event transition leads from one state to another in the dynamic model.

The construction of these models is not sequential, with changes to any one of the models having a knock on effect in the other models. Typically, the designer will start with the object model, then consider the dynamic and finally the functional, but the process is iterative.

The actual analysis process is described in considerable detail and is supported by step by step guidance. This ensures that the developer knows what to do at any time to advance the three models.

### 16.6.2 The Design phase

The Design phase of OMT builds upon the models produced during the analysis phase by breaking them down into subsystems and by identifying appropriate algorithms for methods. These two steps are performed during the system design and object design steps.

* The system design breaks the system down into subsystems and determines the overall architecture to be used.

* The object design decides on the algorithms to be used for the methods. The methods themselves are identified by analyzing the three analysis models for each class etc.

Each of these steps possess some guidelines for their respective tasks, however, far less support is provided for the designer than in the analysis phase. For example, systematic guidance for the identification of subsystems is missing. In stead the issues involved are discussed such as resource management, batch versus interactive modes etc. This means that identifying where to start, how to proceed and what to do next can be difficult.

### 16.6.3 The Implementation phase

The implementation phase represents the process of codifying the system and object designs into the target language. This phase does provide some very useful guidance on how to implement features used in the model-based design process used, but is again lacking in the step by step guidance which would be so useful for those new to object orientation.

### 16.6.4 Strengths and weaknesses

OMTs' greatest strength is the level of step by step support which it provides during the analysis phase. However it is much weaker in its guidance during the design and implementation phases providing general guidance (and some heuristics).

## 16.7 The Objectory method

The Objectory method [Jacobson 1991] possesses three phases each of which produce a set of models. The three phases are: the *Requirements phase*, the *Analysis phase* and the *Construction phase*. The
driving force behind the whole of the Objectory method is the concept of a *use case*. A use case is a particular interaction, between the system and a user of that system, for a particular purpose (or function). The users of the system may be human or machine and are termed *actors*. A complete set of use cases therefore describes a system's functionality based around what actors should be able to do (with the system).

### 16.7.1 The Requirements phase

The Requirements phase uses a natural language description of what the system should do to build three models: the *Use case models*, the *Domain Object model* and the *User Interface descriptions*.

The *use-case model* describes all the interactions between actors and the system. Each use case specifies the actions which are performed and their sequence. Any alternatives are also documented. This can be done in natural language or using state transitions diagrams.

The *domain model* describes the objects, classes and associations between objects in the domain. It uses a modified E-R model.

The *user interface descriptions* contain mock ups of the various interfaces between actors and the system. User interfaces are represented as pictures of windows while other interfaces are described by protocols.

### 16.7.2 The Analysis phase

The Analysis phase produces the analysis model and a set of subsystems. The analysis model is essentially a refinement of the domain object model produced in the last phase. It also contains behavioral information as well as control objects which are linked to use cases. As well as control objects, the analysis model also possesses entity objects (which are objects which exist beyond a single use case) and interface objects which handle system-actor interaction. The subsystem description aims to partition the system around objects which are involved in similar activities and which are closely coupled. This organization is used to structure the remainder of the design process.

### 16.7.3 The Construction phase

The Construction phase refines the models produced in the analysis phase. For example inter object communication is refined as well as consideration of facilities provided by the target language. Four models are produced by this phase:

* Block models which represent the functional modules of the system.

* Block interfaces which specify the public operations performed by blocks.

* Block specifications are optional descriptions of a block behavior in the form of finite state machines.

The final stage is then to implement the blocks in the target language.

### 16.7.4 Strengths and weaknesses

The most significant aspect of Objectory is its use of use-cases. These act as the cement which joins the various building blocks of the whole method. As such Objectory is unique in the methods considered here as it provides a unifying framework for the design process. However, it still lacks the step by step support which would simplify the whole design process.

## 16.8 The Fusion method

The majority of OOD methods currently available, including those described in this chapter, possess some form of systematic approach to the design process. However, in almost all cases this process is rather weak, providing insufficient direction or support to the developer. In addition methods such as OMT rely on a "bottom up" approach. This means that the developer must focus on the identification
of appropriate classes and their interfaces without necessarily having the information to enable them to do this in an appropriate manner for the overall system. For example, little reference is made to the system's overall functionality when determining class functionality etc. Indeed, some methods provide little more than some vague guidelines and anecdotal heuristics.

In contrast, fusion explicitly attempts to provide a systematic approach to object-oriented software development. In many ways the fusion method is a mixture of a range of other approaches (indeed the authors of the method acknowledge that there is little that is new in the approach other than the fact that they have put it all together in a single method, for example see Figure 16.1).

<figure><img src="image_70.png" /><figcaption>Figure 16.1: Some of the influences on Fusion</figcaption></figure>

As with other OOD methods, fusion is based around the construction of appropriate models that capture different elements of the system as well as different knowledge. These models are built up during three distinct phases. The analysis phase, the design phase and the implementation phase:

* The analysis phase produces analysis models which provide a description of the high level constraints from which the design models are developed.

* The design phase produces a set of models that describe how the system behaves in terms of a collection of interacting objects.

* The implementation phase describes how to map the design models onto implementation language constructs.

Within each phase a set of detailed steps attempts to guide the developer through the fusion process. These steps include checks to ensure the consistency and completeness of the emerging design. In addition the output of one step acts as the input for the next.

Fusion's greatest weakness is its complexity - it really requires the use of a sophisticated CASE tool. Without such a tool it is almost impossible to produce a consistent and complete design.

## 16.9 Summary

In this chapter we have reviewed a number of OO analysis and design methods as well as the Unified Modeling Language. We have briefly considered what each offers as well as their strengths and weaknesses. It should be noted that a problem encountered with all these systems is that during the design process it is often difficult to identify commonalities between classes at the implementation level. This means that during any implementation phase, experienced OO technicians should be looking for situations in which they can move to implementation level components up in any class hierarchy. This can greatly increase the amount of reuse within a software system. This may then lead to the introduction of new abstract classes whose role is to contain the common code. The problem with this is that the implemented class hierarchy no longer reflects the design class hierarchy. It is therefore necessary to have a free flow of information from the implementation phase to the design phase and vice versa in an object oriented project.
# 17. The Unified Modeling Language

## 17.1 Introduction

The Unified Modeling Language (or UML for short) is part of a development being carried out to merge the concepts in the Booch, Objectory and OMT methods [Booch and Rumbaugh 1995, Booch et al 1996]. This effort has been termed the unification or the Unified Method. The method is still under development (and has taken a much lower profile recently) however the notation underlying this method is nearing completion. This notation has now become the focus of Booch, Rumbaugh and Jacobson's current work and is receiving a great deal of interest. For example, Microsoft Corporation, Hewlett Packard, Oracle, Texas Instruments have all endorsed the UML.

The UML is a third generation object-oriented modeling language [Rational 1996] which adapts and extends the published notations used in the works of Booch, Rumbaugh and Jacobson [Booch 1994, Rumbaugh et al 1991, Jacobson et al 1992] as well as being influenced by many others (such as Fusion [Coleman et al 1994], Harel's statecharts [Harel et al 1987; Harel 1988] and CORBA [Ben-Natan 1995], see Figure 17.1). It is intended that the UML will form a single, common, widely usable modeling language for a range of object oriented design methods (including Booch, Objectory and OMT). It is also intended that it should be applicable in a wide range of applications and domains. Therefore it should be equally applicable to client-server applications as it is to real-time control applications.

<figure><img src="image_71.png" /><figcaption>Figure 17.1: The influences on the UML notation</figcaption></figure>

Part of the justifications for this is that different organizations, applications and domains require (and use) different design methods. In many cases organizations have developed their own methods or have modified other methods through experience. In some cases different parts of the same organizations may use different methods. The result is that the notation used acts as a language in which ideas represented in part (or all) of the design are expressed and communicated. For example, the production of shrink wrapped, off the shelf software, is different from the creation of one off bespoke software. However both activities may be carried out by a software company. Such an organization may well wish to exchange ideas, designs or parts of designs amongst its various departments or operational units. This kind of exchange relies on the availability of a common language - UML provides such a language.

At present the UML is in draft form [Booch et al 1996], however it is being presented to the OMG (Object Management Group) in the hope that it will be accepted as a standard (this is an on going process and is part of the OMG's call for information on object-oriented methods). For the latest information on the UML (as well as any other developments on the unification front) see the Rational Software Corporation's web site (http://www.rational.com).

This chapter provides a brief introduction to the UML but omits many of the details. For further information on the UML please see version 1.0 of the UML documentation set. There is also a series of books on the UML including a Reference Manual, a User Guide as well as a process book (which at the time of writing were still in the pipe line) that should be referenced for more information.
In the remainder of this chapter we consider how the UML can represent the class, objects, relationships and attributes in an object oriented system. The next chapter considers *sequence* and *collaboration* diagrams, *State diagrams* and *deployment diagrams*.

## 17.2 The UML Infrastructure

The UML is built upon a common metamodel which defines the semantics of the language. On top of this is a common notation which interprets these semantics in an easily (human) comprehensible manner. Each of these is discussed below.

### 17.2.1 The Metamodel

A metamodel describes the constituents of a model and its relationships. That is, it is a model (in its own right) which documents how another model can be defined. Such models are important because they provide a single, common and unambiguous statement of the syntax and semantics of a model. It thus allows CASE tool builders to do more than provide diagramming tools. In fact the metamodel serves several purposes including:

* Defining the syntax and describing the semantics of the UML's concepts.

* Providing a (reasonably) formal basis for the UML.

* Providing a description of the elements of the UML.

* Providing the basis for the interchange of models between vendors' tools.

In the normal course of events a user of the UML (or indeed of a tool which supports the UML) need never know anything about the metamodel. It should be, and is, hidden from sight. However, for the developers of the UML and for tool vendors in general it is a valuable, indeed essential, feature.

At present the UML metamodel is defined in terms of the UML and textual annotations (although this may appear infinitely recursive, it is possible). Work on the metamodel is still progressing with the authors of the UML attempting to make it more formal and simpler.

### 17.2.2 The UML models

The UML defines a number of models and the notations to be used with these models. They are:

**Use case diagrams.** These diagrams are based on the use case diagrams of Objectory and organize the use cases that encompass a system's behavior.

**Class diagrams.** These are derived from the Booch and OMT methods and express the static structure of the system. For example the *part of* and *is a* relationships between classes and objects. Note that the class diagrams also encompass the object diagrams. Therefore, in this book, we will refer to them as the *object model* following the name used in OMT.

**State machine diagrams.** These, like those in OMT, are based on statecharts. They capture the dynamic behavior of the system.

**Sequence diagrams.** Sequence diagrams (formerly known as message-trace diagrams in version 0.8 of the Unified method draft) deal with the time ordered sequence of transactions between objects.

**Collaboration diagrams.** Collaboration diagrams (previously known as Object-message diagrams) indicate the order of messages between specified objects. They are complementary to sequence diagrams as they both illustrate the same information. The difference is that the sequence diagrams have the actual sequence, while the collaboration diagrams have the structure required to support the message sequences.

**Component diagrams.** In version 0.8 of the Unified Method draft these diagrams were called module diagrams. These diagrams represent the development view of the system or how the system should be developed into software modules. They can also be used to represent concepts such as dynamic libraries.
**Deployment diagrams.** Deployment diagrams (previously known as platform diagrams). As this model attempts to capture the topology of the system once it is deployed, it reflects the physical topology upon which the software system is to execute.

## 17.3 Use case diagrams

Use case diagrams explain how a system (or subsystem) will be used. The elements which interact with the system can be humans, other computers or dumb devices which process or produce data. The diagrams thus present a collection of use cases which illustrate what the system is expected to do, in terms of its external services or interfaces. Such diagrams are very important for illustrating overall system functionality (to both technical and non-technical personnel). In addition they can act as the context within which the rest of the system is defined.

<figure><img src="image_72.png" /><figcaption>Figure 17.2: Case-based retrieval system Use Case example</figcaption></figure>

The large rectangle in Figure 17.2, indicates the system's boundaries. The rectangles on either side of the system indicate external actors which interact with the system. In this case the Service Engineer and the Telephonist (this assumes a system being used as a telephone help desk adviser).

The actual notation used for actors is based on what are called stereotypes (stereotypes are discussed in more detail later in this chapter). Actors are in fact classes with stereotypes. The <<actor>> indicates the actor stereotype and the stick figure is the actor stereotype icon. Although we have used the class icon (a box) as well as the stereotyp e icon (the stick man) we could have used only one of them if we had so wished.

The ovals inside the system box in Figure 17.2 indicate the actual use cases themselves. For example, both the actors will wish to be able to “load a casebase”. Each individual use case can have a name, have a description explaining what it does as well as a list of its responsibilities, attributes and operations. They may also describe their behavior in the form of a state chart. The most ap propriate form of description for a use case will differ from one domain to another and thus the format should be chosen as appropriate. This illustrates the flexibility of the UML as it does not prescribe the actual format of a use case.

It is also possible to use sequence diagrams and collaboration diagrams with use case diagrams to illustrate the sequence of interactions between the system and the actors. Use cases should also be annotated with a statement of purpose to place the use case itself in some overall context.

Finally, the relationship between use case diagrams and class diagrams is that use cases are peers of classes. Depending on the size of the system, they can be grouped with the object model in a package or remain totally independent.

## 17.4 The object model

This is really the key element of a UML model. The constituent diagrams illustrate the static structure of a system via the important classes and objects in the system and how they relate to each other. The UML documentation currently talks about class diagrams (and within this about object diagrams) stating that “class diagrams show generic descriptions of possible systems and object diagrams show particular instantiations of systems and their behavior”. They go on to state that class diagrams contain
classes, while object diagrams contain objects, but that it is possible to mix the two. However, they discuss both under the title *class diagrams*. Therefore, to avoid confusion, we adopt the term Object Model to cover both sets of diagrams (following the approach adopted in both the Booch and OMT methods).

### 17.4.1 Classes and objects

A class is drawn as a solid -outline rectangle with three components. The class name (in bold type) is in the top part, a list of attributes (with optional types and initial values) in the middle part and a list of operations (with argument types and return values) in the bottom part. Figure 17.3 illustrates two classes, one for a class Car and one for a class File. The Car class possesses three attributes called name, age and fuel. Their types are string, integer and string respectively. The class also possesses four operations start(), lock() and brake(), plus accelerate which takes a single parameter “to” which is an integer and represents the new speed.

Car
name: string
age: integer
fuel: string

start()
lock()
accelerate(to:integer)
brake()

File
filename: string
size: integer
lastUpdate: string

print()

<caption>Figure 17.3: Class with attributes and operations</caption>

An attribute has a name and a type specified in the format `name: type = initialValue`. The name and type are strings that are ultimately language dependent. The initial value is a string representing an expression in the target language. Operations have a name and may take one or more parameters and return a value. The format of an operation is `name (parameter: type = defa ultValue, ...): resultType`. The operation's constituent parts are strings that are language dependent.

The attribute and operation compartments can be *hidden* from view to reduce the detail shown in a diagram. Omitting a compartment says nothing about that part of the class definition. However, leaving a compartment blank implies that there are no definitions for that part of the class. Additional language dependent and user-defined information can also be included in each compartment in a textual format. The intention of such additions is to clarify any element of the design in a similar manner to a comment in source code.

The class *stereotype* can be shown as a normal-font text string in between `<< >>` centered above the class name (see Figure 17.4). A stereotype tells the reader what “kind” of class it is. Examples of stereotypes are *exceptions*, *controllers*, *interfaces* etc. However, UML makes no assumptions about the range of stereotypes which exist and the designer is therefore free to develop their own. Other (language specific) class properties can also be indicated in the class name compartment. For example in Figure 17.4 the Window class is an abstract class, thus the label abstract is printed below (and to the left) of the class name.
<figure><img src="image_73.png" /><figcaption>Figure 17.4: Class with additional annotations</figcaption></figure>

Attributes and operations can also have their intended scope indicated in the class definition. This can be useful even for languages such as Smalltalk which do not support concepts such as Public, Private and Protected attributes and operations. The absence of any symbol at all in front of an attribute or operation indicates that the element is a public instance attribute or operation for that class. The significance of this depends on the language. The range of symbols currently supported is indicated in Figure 17.4 and combinations of symbols can be used to indicate (for example) that a method is a class side public method (such as `$new()` - a class side operation intended for instance creation).

<figure><img src="image_74.png" /><figcaption>Figure 17.5: An object (structured cloud)</figcaption></figure>

An object is drawn as a hexagon with straight sides and a slight peak at the top and bottom (as illustrated in Figure 17.5). For those familiar with the Booch clouds this can be thought of as a structured cloud otherwise just accept that this is the object symbol<fnref n="10" />. The object symbol can be divided into two sections. The top section indicates the name of the object and its class in the format `objectName: className`. For example, in Figure 17.5 the object is `repMobile1` and the class is `Car` (see Figure 17.3 for the definition of the class `Car`). The object name is optional although the class name is compulsory. The lower compartment contains a list of attributes and their values in the format `name type = value` (although the type is usually omitted). For example in Figure 17.5 the three attributes defined in Figure 17.3 for a `Car` have the values `XK8`, `1` and `petrol`. The bottom compartment can be suppressed for clarity. It is also possible to indicate how many objects of a particular class are anticipated. This is done by indicating the maximum value, range etc. in the top compartment. The lack of any number indicates that a single object is intended.

## 17.4.2 Associations

Relationships between classes and objects are represented by associations drawn as a solid line between classes or objects (for example see Figure 17.6). An association between classes may have a name with an optional small “direction arrow head” (which is drawn as an arrow head on the association) showing which way it is to be read. For example in Figure 17.6 the relationship is called `hasEngine` and is read from the class `Car` to the class `Engine`. In addition each end of an association is a **role**. Roles may have a name illustrating how its class is viewed by the other class. In Figure 17.6 the engine sees the car as being a name and the car sees the engine as being of a specified type (e.g. Petrol, Diesel, Electric etc.).

<footnote n="10">¹⁰ Note that as of September 1996, the 0.91 addendum to the UML states that objects are now drawn as rectangles with the object name and its class name (separated by a colon) underlined. This is a major notational change which the authors of the UML wish to make so that they do not have to invent different symbols every time they have a type (or class) - instance relationship. However this means that the distinction between objects and classes in diagrams is minimal and can easily lead to confusion. In an attempt to make objects clearly distinguishable in this, and subsequent diagrams, we shall continue to use the structured cloud symbol for objects.</footnote>
<figure><img src="image_75.png" /><figcaption>Figure 17.6: Association between classes / link between objects</figcaption></figure>

Each role (i.e. each end of the association) indicates the multiplicity of its class (i.e. how many instances of the class can be associated with one instance of the other class). This is indicated by a text expression on the role. The expression can either be a * (indicating zero or more), a number (e.g. 1), a range (e.g. 0..3) or nothing (indicating exactly 1). These expressions are illustrated in Figure 17.7. It is also possible to specify that the multiple objects should be ordered using the text {Ordered}. It is also possible to annotate the association with additional text (such as {Sorted}) but this is primarily for the readers benefit and has no semantic meaning in UML.

In some situations it is sensible for associations to have attributes of their own. In these situations associations need to be treated as a class. Such a situation is illustrated in Figure 17.8. These associations have a dashed line from the association line to the association class. This class is just like any other class and can have a name, attributes and operations.

<figure><img src="image_76.png" /><figcaption>Figure 17.7: Types of association annotations</figcaption></figure>

In Figure 17.8 the associations possess an access permissions attribute which indicates the type of access allowed for each user for each file.

<figure><img src="image_77.png" /><figcaption>Figure 17.8: Associations with attributes</figcaption></figure>

Aggregation represents *part-whole* relationships. That is, it indicates that one or more objects are dependent on another object for their existence. For example, in Figure 17.9 the Micro Computer is formed from the Monitor, the System box, the Mouse and the Keyboard. All of these objects together are needed for the fully functioning Computer. Aggregation is actually represented as an empty diamond on the role attached to the whole object.
<figure><img src="image_78.png" /><figcaption>Figure 17.9: Aggregation tree notation</figcaption></figure>

A qualified association is an association which requires both the object and the qualifier to uniquely identify the object involved in the association. It is represented as a box between the association and the class. For example, in Figure 17.10, it is necessary to use the catalog and the part number to identify a unique part. Note that the qualifier is part of the association, not the class.

<figure><img src="image_79.png" /><figcaption>Figure 17.10: Qualified associations</figcaption></figure>

Ternary (or indeed higher order) associations are drawn as diamonds with one line path to each of the participating classes (for example see Figure 17.11). This is actually the traditional entity - relationship model symbol for an association (the diamond is omitted from the binary form to save space). Ternary associations are very rare and higher order associations are almost none existent. However, the facility to model them is available.

<figure><img src="image_80.png" /><figcaption>Figure 17.11: Ternary Associations</figcaption></figure>

It is sometimes useful to differentiate between by -value references and by -reference ones. This is done using the aggregation symbol. If the aggregation symbol is hollow, it indicates a by -reference implementation (i.e. a pointer or other reference); if the aggregation symbol is filled, it indicates a by -value implementation, i.e. a class that is embedded within another class (see Figure 17.12).

<figure><img src="image_81.png" /><figcaption>Figure 17.12: Implementation adornment</figcaption></figure>

Inheritance of one class by a subclass is indicated by a solid line drawn from the subclass to the superclass with a large (unfilled) triangular arrowhead on the superclass end (see Figure 17.13). For
compactness a tree structure can be used to show multiple subclasses inheriting from a single superclass.

<figure><img src="image_82.png" /><figcaption>Figure 17.13: Inheritance: specialization - generalization</figcaption></figure>

Multiple inheritance can also be modeled as languages such as CLOS (the Common Lisp Object System) and C++ support it. This is done by drawing multiple inheritance lines from a single subclass to two or more super classes as in Figure 17.14. In this figure the class *Motor powered water vehicle* inherits from both *Motor powered* and *Water vehicle*.

<figure><img src="image_83.png" /><figcaption>Figure 17.14: Multiple Inheritance</figcaption></figure>

Derived values can be represented by a slash ('/' ) in front of the name of the derived attribute. Such an attribute requires an additional textual constraint defining how it is generated (as in Figure 17.15). This is indicated by a textual annotation below the class between curly ( { } ) brackets.

<table>
  <tr>
    <td>Person</td>
  </tr>
  <tr>
    <td>birthdate</td>
  </tr>
  <tr>
    <td>/age</td>
  </tr>
</table>

{age = currentDate - birthdate}

<caption>Figure 17.15: Derived values</caption>
<figure><img src="image_84.png" /><figcaption>Figure 17.16: Example composites</figcaption></figure>

A class may define a pattern of objects and links that are part of it and that exist whenever the class is instantiated. Such a class is called a composite. It is a class that contains an object diagram. It may be thought of as an extended form of aggregation where the relationships among the parts are valid only within the composite. A composite is a kid of *pattern* or *macro* that represents a conceptual clustering for a given purpose. Composition is shown by drawing a class box around its embedded components (as illustrated in Figure 17.16) which are prototypical objects and links. That is, a composite defines a context in which references to classes and associations, defined elsewhere, can be used.

## 17.5 Packages

Packages are used to group associated modeling elements such as classes in the object model (or subsystems in component diagrams). They are drawn as tabbed folders as illustrated in Figure 17.17.

Figure 17.17 actually illustrates four packages called *clients*, *Business model*, *Persistent store*, *Bank* and *Network*. In this particular diagram the contents of *Clients*, *Persistent Store*, *Bank* and *Network* have been suppressed (by convention these packages have their names placed in their body) with only *Business Model* being shown in detail (with its name in the top tab). This package possesses two classes *Customer* and *Account* as well as a nested package *Bank*. The dashed lines between the packages illustrate dependencies between packages. For example, the package *Clients* directly depends on the packages *Business Model* and *Network* (this actually means that at least one element in the package *Clients* relies on at least one element in the other two packages).

<figure><img src="image_85.png" /><figcaption>Figure 17.17: Packages with Dependencies</figcaption></figure>

Classes may belong to exactly one package but references may be made to classes in other packages. Such references have the package name followed by the class name (separated by two colons), for example: *Business Model*:: *Customer*.
Packages allow models to be structured hierarchically, they therefore act to organize the model and control its overall complexity. Indeed packages may be used to enable top down design of a system (rather than the bottom up design typical of many OOD methods) by allowing designers to specify high level system functionality in terms of packages which are “filled out” when and as appropriate.
# 18. UML: Dynamic Modeling And Deployment

## 18.1 Introduction

The basic class and association notations of the object model in the Unified Modeling Language (or UML for short) were presented in the last chapter. This chapter presents the *sequence, collaboration* diagrams and *state diagrams* as part of the dynamic modeling facilities in the UML. We then consider *deployment diagrams*.

## 18.2 Dynamic modeling facilities

### 18.2.1 Sequence diagrams

A *scenario* shows a particular series of interactions among objects in a single execution of a system. That is, it is a history of how the system behaved from one start state to a single termination state. This differs from an *envisionment* which is a description of all system behaviors from all start states to all end states. Envisionments thus contain all possible histories (although they may also contain paths which the system is never intended to take).

Scenarios can be presented in two different ways: *Sequence Diagrams* and *Collaboration Diagrams*. Both these diagrams present the same information although they stress different aspects of this information. For example, sequence diagrams stress the timing aspects of the interactions amongst the objects, where as the collaboration diagrams stress the structure between these objects (which helps in understanding the requirements of the underlying software structure).

Figure 18.1 illustrates the basic structure of a sequence diagram. The objects involved in the exchange of messages are represented as vertical lines (which are labeled with the object's name). For example, Caller, Phone Line and Callee are all objects involved in the scenario of dialing 999 (the Emergency services' number in the UK). Time proceeds vertically down the diagram, as indicated by the dashed line arrow. The horizontal arrows indicate an event or message sent from one object to another. The arrow indicates the direction in which the event or message is sent. That is, the receiver is indicated by the head of the arrow. Normally return values are not shown on these diagrams. However, if they are significant, they can be illustrated by return events annotated with the type of value returned etc.

Time proceeds vertically and can be made more explicit by additional timing marks. These timing marks indicate how long the gap between messages should be or how long a message or event should take to get from the sender to the receiver.
<figure><img src="image_86.png" /><figcaption>Figure 18.1: A sequence diagram</figcaption></figure>

A variation of the basic sequence diagram (called a focus -of-control diagram) illustrates which object has the thread of control at any one time. This is shown by a fatter line during the period when the object has control (as illustrated in Figure 18.2). Note how the bar representing the object C only starts when it is created and terminates when it is destroyed.

<figure><img src="image_87.png" /><figcaption>Figure 18.2: Sequence diagram with focus-of-control regions</figcaption></figure>

### 18.2.2 Collaboration diagrams

As stated above, collaboration diagrams illustrate the sequence of messages between objects based around the object structure (rather than the temporal aspects of sequence diagrams). A collaboration diagram is formed from the objects involved in the collaboration, the links (permanent or temporary) between the objects and the messages (numbered in sequence) that are exchanged between the objects. An example collaboration diagram is presented in Figure 18.3.
<figure><img src="image_88.png" /><figcaption>Figure 18.3: An example collaboration diagram</figcaption></figure>

Objects which are created during the collaboration are indicated by the label *new* before the object name. For example the Line object in Figure 18.3. Links between objects are annotated to indicate their type (e.g. permanent or temporary existing for this particular collaboration). These adornments are placed in boxes on the ends of the links and can have the following values:

* A - association (or permanent) link

* F - Object field (the target object is part of the source object)

* G - global variable

* L - local variable

* P - Procedure parameter

* S - self reference

Role names can also be added to distinguish links (e.g. self, wire and window in Figure 18.3). Role names in brackets indicate a temporary link, i.e. one that is not an association.

The messages which are sent along links are indicated by labels next to the links. One or more messages can be sent along a link in either or both directions. The format of the messages is defined by the following (some of which are optional):

1. A comma-separated list of sequence numbers in brackets: [seqno, seqno]. The sequence numbers indicate messages from other threads of control that must occur before the current message can occur. This element is only needed with concurrency.

2. A sequence number containing a list of sequence elements separated by *full stops (periods)*. These represent the nested procedural calling sequence of the message in the overall transaction. Each element section has the following parts:

* A letter (or name) indicating a concurrent thread. All letters at the same level of nesting represent threads that execute concurrently e.g. 1.2a and 1.2b are concurrent. Omitting the letter entirely is equivalent to another dummy letter and usually indicates the main sequence.

* An integer number. The numbers show the sequential position of the current message within its thread. For example, message 2.1.4 is part of the procedure invoked by message 2.1 and follows message 2.1.3 within that procedure.

* An iteration indicator. This is a star (*), optionally followed by an iteration expression in parentheses. Iteration indicates that several messages of the same form are sent either sequentially (to a single target) or concurrently (to the elements of a set). If there is an iteration expression, it shows the values that the iterator or iterators assume, such as "(i=1..n)"; otherwise the details of the iteration must be specified in text or simply deferred to the code.