enumerating

**do: aBlock**

contents associationsDo:

[:assoc | assoc value timesRepeat: [aBlock value: assoc key]]]

Class Set

The elements of Sets are unordered like those of Bags, so the messages at: and at:put: produce an error report. A Set may not contain an element more than once, therefore, every insertion of an element must, in theory, check the entire collection. To avoid searching all elements, a Set determines where in its indexed instance variables to start a search for a particular element by using a hashing technique.

Each Set has an instance variable named tally. Maintaining this tally of the number of elements avoids the inefficiencies involved in determining the size of the Set by counting every non-nil element. Thus new, new:, and size are reimplemented; the first two in order to initialize the variable tally and the last simply to respond with the value of tally.

<table><tr><td>class name</td><td>Set</td></tr><tr><td>superclass</td><td>Collection</td></tr><tr><td>instance variable names</td><td>tally</td></tr><tr><td>class methods</td><td></td></tr></table>

instance creation

**new**

↑self new: 2

**new: anInteger**

↑(super new: anInteger) setTally

instance methods

accessing

**at: index**

self errorNotKeyed

**at: index put: anObject**

self errorNotKeyed

**size**

↑tally

private

**setTally**

tally ← 0

In the method for new:, super is used in order to avoid recursion. A private message of Set, findElementOrNil:, hashes the argument to produce the index at which to begin the probe of the Set. The probe proceeds until the argument, anObject, is found, or until nil is encountered. The
response is the index of the last position checked. Then the testing messages are implemented as

testing

**includes: anObject**

↑(self basicAt: (self findElementOrNil: anObject)) ~ nil

**occurrencesOf: anObject**

(self includes: anObject)

ifTrue: [↑1]

ifFalse: [↑0]

The number of occurrences of any element in the Set is never more than 1. The three basic messages must make use of basicAt: and basicAt:put: because Sets report an error if at: or at:put: is used.

adding

**add: newObject**

| index |

newObject isNil ifTrue: [↑newObject].

index ← self findElementOrNil: newObject.

(self basicAt: index) isNil

ifTrue: [self basicAt: index put: newObject. tally ← tally + 1].

↑newObject

removing

**remove: oldObject ifAbsent: aBlock**

| index |

index ← self find: oldObject ifAbsent: [↑aBlock value].

self basicAt: index put: nil.

tally ← tally - 1.

self fixCollisionsFrom: index.

↑oldObject

enumerating

**do: aBlock**

1 to: self basicSize do:

| :index |

(self basicAt: index) isNil

ifFalse: [aBlock value: (self basicAt: index)]]

The private message find:ifAbsent: calls on findElementOrNil; if the element, oldObject, is not found, the argument aBlock is evaluated. In order to guarantee that the hashing/probing technique works properly, remaining elements might need to be compacted whenever one is removed (fixCollisionsFrom:). These methods are good examples of when the accessing messages basicAt:, basicAt:put:, and basicSize must be used.
## Class Dictionary

A Dictionary is a collection of Associations. Class Dictionary uses a hashing technique to locate its elements which is like that of its superclass, Set, but hashes on the keys in the Associations instead of on the Associations themselves. Most of the accessing messages for Dictionary are reimplemented to treat the values of the Associations as the elements, not the Associations themselves.

Dictionary implements `at:` and `at:put;`, but redefines the argument associated with the keyword `at:` to be any key in the Dictionary (not necessarily an `Integer` index). The argument of includes: is the value of one of the Associations in the Dictionary, not one of the Associations themselves. The message `do:` enumerates the values, not the Associations. The argument to remove: is also a value, but this is an inappropriate way to delete from a Dictionary because elements are referenced with keys. Either `removeAssociation:` or `removeKey:` should be used. Thus the messages `remove:` and `remove:ifAbsent:` should not be implemented for `Dictionary`.

Much of the work in the accessing protocol is done in private messages, either those inherited from `Set` or similar ones for finding a key (`findKeyOrNil:`).

<table><tr><td>class name</td><td>Dictionary</td></tr><tr><td>superclass</td><td>Set</td></tr><tr><td>instance methods</td><td></td></tr></table>

### accessing

#### at: key

`↑self at: key ifAbsent: [self errorKeyNotFoundError]`

#### at: key put: anObject

| index element |
index → self findKeyOrNil: key.
element → self basicAt: index.
element isNil
ifTrue:
    [self basicAt: index put: (Association key: key value: anObject).
        tally ← tally + 1]
    "element is an Association. The key already exists, change its
        value."
ifFalse:
    [element value: anObject].

↑anObject

#### at: key ifAbsent: aBlock

| index |
index → self findKey: key ifAbsent: [↑aBlock value].
↑(self basicAt: index) value
testing

**includes: anObject**

"Revert to the method used in Collection."

self do: [ :each | anObject = each ifTrue: [true]].
self false

adding

**add: anAssociation**

| index element |
index ← self findKeyOrNil: anAssociation key.
element ← self basicAt: index.
element isNil
  ifTrue: [self basicAt: index put: anAssociation.
        tally ← tally + 1]
ifFalse: [element value: anAssociation value].
tanAssociation

removing

**remove: anObject ifAbsent: aBlock**

self shouldNotImplement

enumerating

**do: aBlock**

self associationsDo: [ :assoc | aBlock value: assoc value]

private

**errorKeyNotFoundError**

self error: 'key not found'

Notice the similarity between at:put: and add:. The difference is in the
action taken if the element is not found—in the case of at:put:, a new
Association is created and stored in the Dictionary; in the case of add:
the argument, anAssociation, is stored so that any shared reference to
the Association is preserved.

The message collect: is reimplemented in order to avoid the problems
of collecting possibly identical values into a Set which would result in
throwing away duplications. The message select: is reimplemented in
order to select Associations by applying their values as the arguments
to the block.

enumerating

**collect: aBlock**

| newCollection |
newCollection ← Bag new.
self do: [ :each | newCollection add: (aBlock value: each)].
tnewCollection
**select: aBlock**

| newCollection |
newCollection ← self species new.
self associationsDo:
    [ :each |
        (aBlock value: each value) ifTrue: [newCollection add: each]].
↑newCollection

IdentityDictionary overrides at:, at:put:, and add: in order to implement checking for identical keys instead of equal keys. An IdentityDictionary is implemented as two parallel ordered collections of keys and values, rather than as a single collection of Associations. Thus do: must also be reimplemented. The implementation is not shown.

**Sequenceable-Collections**

SequenceableCollection is the superclass for all collections whose elements are ordered. Of the messages we are examining, remove:ifAbsent: is specified as being inappropriate for SequenceableCollections in general, since the order of elements might have been externally specified and it is assumed that they should be removed in order. Because SequenceableCollections are ordered, elements are accessed using at:; the implementation is provided in class Object. The message do: is implemented by accessing each element at index 1 through the size of the collection. SequenceableCollections are created using the message new:. Therefore, collect: and select: must be reimplemented to create the new collection using new: rather than new. The methods for collect: and select: shown next use a WriteStream in order to access the new collection, and the message at: in order to access elements of the original collection.

<table><tr><td>class name</td><td>SequenceableCollection</td></tr><tr><td>superclass</td><td>Collection</td></tr><tr><td>instance methods</td><td></td></tr></table>

accessing

**size**

self subclassResponsibility

removing

**remove: oldObject ifAbsent: anExceptionBlock**

self shouldNotImplement

enumerating

**do: aBlock**

| index length |
index ← 0.
length ← self size.
[(index ← index + 1) <= length]
while True: [aBlock value: (self at: index)]

**collect: aBlock**

| aStream index length |
aStream ← WriteStream on: (self species new: self size).

index ← 0.

length ← self size.

[(index ← index + 1) <= length]
while True: [aStream nextPut: (aBlock value: (self at: index))].

↑aStream contents

**select: aBlock**

| aStream index length |
aStream ← WriteStream on: (self species new: self size).

index ← 0.

length ← self size.

[(index ← index + 1) <= length]
while True:

[(aBlock value: (self at: index))
ifTrue: [aStream nextPut: (self at: index)]]].

↑aStream contents

Notice that size is declared as a subclass responsibility in SequenceableCollection. The method inherited from the superclass Collection uses `do:` to enumerate and thereby count each element. But the method for `do:` as specified in SequenceableCollection determines the limit for indexing by requesting the size of the collection. Therefore, size must be reimplemented in order not to be stated in terms of `do`:

□ **Class** `LinkedList` Elements of `LinkedList` are instances of `Link` or of one of its subclasses. Each `LinkedList` has two instance variables, a reference to the first and to the last elements. Adding an element is assumed to be interpreted as adding to the end (`addLast`); the method for `addLast:` is to make the element the next link of the current last link. Removing an element means that the element's preceding link must reference the element's succeeding link (or `nil`). If the element to be removed is the first one, then its succeeding link becomes the first one.

<table><tr><td>class name</td><td>LinkedList</td></tr><tr><td>superclass</td><td>SequenceableCollection</td></tr><tr><td>instance variable names</td><td>firstLink<br/>lastLink</td></tr></table>

instance methods

accessing

**at: index**

| count element size |

count ← 1.

Subclasses of
Sequenceable-
Collection
element ← self first.

size ← self size.

[count > size] whileFalse:

[count = index
    ifTrue: [element]
    ifFalse: [count ← count + 1.
               element ← element nextLink]].

↑self errorSubscriptBounds: index

**at: index put: element**

self error: 'Do not store into a VIN linked list using at:put:'

adding

**add: aLink**

↑self addLast: aLink

**addLast: aLink**

self isEmpty
    ifTrue: [firstLink ← aLink]
    ifFalse: [lastLink nextLink: aLink].

lastLink ← aLink.

↑aLink

removing

**remove: aLink ifAbsent: aBlock**

| tempLink |
aLink == firstLink
    ifTrue:
        [firstLink ← aLink nextLink.
         aLink == lastLink ifTrue: [lastLink ← nil]]

ifFalse:
    [tempLink ← firstLink.
    [tempLink isNil ifTrue: [↑aBlock value].
     tempLink nextLink == aLink]
     whileFalse: [tempLink ← tempLink nextLink].

tempLink nextLink: aLink nextLink.

aLink == lastLink ifTrue: [lastLink ← tempLink]].

aLink nextLink: nil.

↑aLink

enumerating

**do: aBlock**

| aLink |
aLink ← firstLink.
[aLink isNil] whileFalse:
    [aBlock value: aLink.
     aLink ← aLink nextLink]
A nil link signals the end of the `-linkedList`. Thus the enumerating message `do:` is implemented as a simple loop that continues until a `nil` is encountered in the collection.

□ *Class Interval Intervals* are *SequenceableCollections* whose elements are computed. Therefore, messages for adding and removing cannot be supported. Since elements are not explicitly stored, all accessing (`at`, `size`, and `do:`) requires a computation. Each method checks to see if the last element computed is to be incremented (positive step) or decremented (negative step) in order to determine whether the limit (`stop`) has been reached.

<table><tr><td>class name</td><td>Interval</td></tr><tr><td>superclass</td><td>SequenceableCollection</td></tr><tr><td>instance variable names</td><td>start<br>stop<br>step</td></tr></table>

class methods

instance creation

**from: startinteger to: stopinteger**

↑self new
  setFrom: startinteger
  to: stopinteger
  by: 1

**from: startinteger to: stopinteger by: stepinteger**

↑self new
  setFrom: startinteger
  to: stopinteger
  by: stepinteger

instance methods

accessing

**size**

step < 0
  ifTrue: [start < stop
    ifTrue: [↑0]
    ifFalse: [↑stop - start // step + 1]]
  ifFalse: [stop < start
    ifTrue: [↑0]
    ifFalse: [↑stop - start // step + 1]]

**at: index**

(index >= 1 and: [index <= self size])
  ifTrue: [↑start + (step * (index - 1))]
  ifFalse: [self errorSubscriptBounds: index]
**at: index put: anObject**

self error: 'you cannot store into an Interval'

adding

**add: newObject**

self error: 'elements cannot be added to an Interval'

removing

**remove: newObject**

self error: 'elements cannot be removed from an Interval'

enumerating

**do: aBlock**

| aValue |

aValue ← start.

step < 0

ifTrue: [[stop <= aValue]

whileTrue: [aBlock value: aValue.
            aValue ← aValue + step]]

ifFalse: [[stop >= aValue]

whileTrue: [aBlock value: aValue.
            aValue ← aValue + step]]

**collect: aBlock**

| nextValue i result |

result ← self species new: self size.

nextValue ← start.

i ← 1.

step < 0

ifTrue: [[stop <= nextValue]

whileTrue:
    [result at: i put: (aBlock value: nextValue).
    nextValue ← nextValue + step.
    i ← i + 1]]

ifFalse: [[stop >= nextValue]

whileTrue:
    [result at: i put: (aBlock value: nextValue).
    nextValue ← nextValue + step.
    i ← i + 1]].

↑result

private

**setFrom: startInteger to: stopInteger by: stepInteger**

start ← startInteger.

stop ← stopInteger.

step ← stepInteger.
□ **ArrayedCollections**—Array, **byteArray**, **String**, **Text**, and **Symbol**
**ArrayedCollection** is a subclass of **SequenceableCollection**; each
**ArrayedCollection** is a variable-length object. All instance creation
methods are reimplemented to use new:, not new. **ArrayedCollections** are
fixed-length so add: is disallowed; in its superclass, remove: was already
disallowed and do: was implemented. Only size, therefore, is
implemented in **ArrayedCollection**—it is a system primitive that reports
the number of indexed instance variables.

Of the subclasses of ArrayedCollection, Array, and BeanArray do not
reimplement any of the messages we are examining in this chapter.
Accessing messages for String—at:, at:put:, and size—are system primi-
tives; in Text, all accessing messages are passed as messages to the in-
stance variable string (which is an instance of String). Symbol disallows
at:put: and returns String as its species.

□ **OrderedCollections** and **SortedCollections**
**OrderedCollection** stores
an ordered, contiguous sequence of elements. Since **OrderedCollections**
are expandable, some efficiency is gained by allocating extra space for
the sequence. Two instance variables, **firstIndex** and **lastIndex**, point to
the first and the last actual elements in the sequence.

The index into OrderedCollection is converted to be within the range
of firstIndex to lastIndex for accessing messages (at: and at:put:) and the
size is simply one more than the difference between the two indices.
Adding an element is interpreted to be adding to the end; if there is no
room at the end, the collection is copied with additional space allocated
(makeRoomAtLast is the private message that does this work). The actu-
al location for storing an element is the computed index position after
lastIndex. If an element is removed, then the remaining elements must
be moved up so that elements remain contiguous (removeIndex:).

<table>
   <tr>
    <td>
     class name
    </td>
    <td>
     OrderedCollection
    </td>
   </tr>
   <tr>
    <td>
     superclass
    </td>
    <td>
     SequenceableCollection
    </td>
   </tr>
   <tr>
    <td>
     instance variable names
    </td>
    <td>
     firstIndex
     <br/>
     lastIndex
    </td>
   </tr>
   <tr>
    <td colspan="2">
     class methods
    </td>
   </tr>
   <tr>
    <td colspan="2">
     instance creation
    </td>
   </tr>
  </table>

new

`tself new: 10`

new: anInteger

`t(super new: anInteger) setIndices`

instance methods

accessing

size

`tlastIndex - firstIndex + 1`
**at: anInteger**

(anInteger < 1 or: [anInteger + firstIndex - 1 > lastIndex])
ifTrue: [self errorSuchElement]
ifFalse: [super at: anInteger + firstIndex - 1]

**at: anInteger put: anObject**

| index |
index -> anInteger truncated.
(index < 1 or: [index + firstIndex - 1 > lastIndex])
ifTrue: [self errorSuchElement]
ifFalse: [super at: index + firstIndex - 1 put: anObject]

adding

**add: newObject**

↑self addLast: aLink

**addLast: newObject**

lastIndex = self basicSize ifTrue: [self makeRoomAtLast].
lastIndex -> indexes + 1.
self basicAt: indexes put: newObject.
↑newObject

removing

**remove: oldObject ifAbsent: absentBlock**

| index |
index -> firstIndex.
[index <= indexes]
whileTrue:
[oldObject = (self basicAt: index)
ifTrue: [self removeIndex: index.
          ↑oldObject]
ifFalse: [index -> index + 1]].
↑absentBlock value

private

**setIndices**

firstIndex -> self basicSize // 2 max: 1.
lastIndex -> firstIndex - 1 max: 0

**errorSuchElement**

self error:
'attempt to index non-existent element in an ordered collection'

The enumerating messages do:, collect:, and select: are each reimplemented—do: in order to provide better performance than the method provided in SequenceableCollection.
enumerating

**do: aBlock**

| index |
index -> firstIndex.
[index <= lastIndex]

while True:

[aBlock value: (self basicAt: index).
index -> index + 1]

**collect: aBlock**

| newCollection |
newCollection -> self species new.
self do: [ :each | newCollection add: (aBlock value: each)].
t newCollection

**select: aBlock**

| newCollection |
newCollection -> self copyEmpty.
self do: [ :each | (aBlock value: each) ifTrue: [newCollection add: each]].
t newCollection

In the method for select:, the new collection is created by sending the original collection the message copyEmpty. This message creates a new collection with enough space allocated to hold all the elements of the original, although all the elements might not be stored. In this way, time taken in expanding the new collection is avoided.

SortedCollection is a subclass of OrderedCollection. The message at:put: reports an error, requesting the programmer to use add; add: inserts the new element according to the value of the instance variable sortBlock. The determination of the position for insertion is done as a "bubble sort." collect: is also reimplemented to create an OrderedCollection rather than a SortedCollection for collecting the values of the block. The code is not shown; a bubble sort looks the same in Smalltalk-80 as it would in most programming languages.

Class
MappedCollection

Instances of MappedCollection have two instance variables—domain and map. The value of domain is either a Dictionary or a SequenceableCollection; its elements are accessed indirectly through map. The message add: is disallowed. Both at: and at:put: are reimplemented in MappedCollection in order to support the indirect access from map to the elements of domain. The size of a MappedCollection is the size of its domain.

<table><tr><td>class name</td><td>MappedCollection</td></tr><tr><td>superclass</td><td>Collection</td></tr><tr><td>instance variable names</td><td>domain</td></tr><tr><td></td><td>map</td></tr></table>
class methods

instance creation

**collection: domainCollection map: mapCollection**

↑super new setCollection: domainCollection map: mapCollection

**new**

self error: 'use collection:map: to create a MappedCollection'

instance methods

accessing

**at: anIndex**

↑domain at: (map at: anIndex)

**at: anIndex put: anObject**

↑domain at: (map at: anIndex) put: anObject

**size**

↑map size

adding

**add: newObject**

self shouldNotImplement

enumerating

**do: aBlock**

map do:

[ :mapValue | aBlock value: (domain at: mapValue)]

**collect: aBlock**

| aStream |

aStream ← WriteStream on: (self species new: self size).

self do: [ :domainValue |

aStream nextPut: (aBlock value: domainValue)].

↑aStream contents

**select: aBlock**

| aStream |

aStream ← WriteStream on: (self species new: self size).

self do:

[ :domainValue |

(aBlock value: domainValue)

ifTrue: [aStream nextPut: domainValue]].

↑aStream contents

private

**setCollection: domainCollection map: mapCollection**

domain ← domainCollection.

map ← mapCollection

**species**

↑domain species
14

Kernel Support Classes

Class UndefinedObject

Classes Boolean, True, and False

Additional Protocol for Class Object

Dependence Relationships Among Objects

Message Handling

System Primitive Messages

<figure><img src="image_122.png" /></figure>
Object

Magnitude

Character

Date

Time

Number

Float

Fraction

Integer

LargeNegательInteger

LargePositivelnteger

SmallInteger

LookupKey

Association

Link

Process

Collection

SequenceableCollection

LinkedList

Semaphore

ArrayedCollection

Array

Bitmap

DisplayBitmap

RunArray

String

Symbol

Text

ByteArray

Interval

OrderedCollection

SortedCollection

Bag

MappedCollection

Set

Dictionary

IdentityDictionary

Stream

PositionableStream

ReadStream

WriteStream

ReadWriteStream

ExternalStream

FileStream

Random

File

FileDirectory

FilePage

UndefinedObject

Boolean

False

True

ProcessorScheduler

Delay

SharedQueue

Behavior

ClassDescription

Class

MetaClass

Point

Rectangle

BitBit

CharacterScanner

Pen

DisplayObject

DisplayMedium

Form

Cursor

DisplayScreen

InfiniteForm

OpaqueForm

Path

Arc

Circle

Curve

Line

LinearFit

Spline
**Class**
**UndefinedObject**

The object nil represents a value for uninitialized variables. It also represents meaningless results. It is the only instance of class UndefinedObject.

The purpose of including class UndefinedObject in the system is to handle error messages. The typical error in evaluating Smalltalk-80 expressions is that some object is sent a message it does not understand. Often this occurs because a variable is not properly initialized—in many cases, the variable name that should refer to some other object refers to nil instead. The error message is of the form

`ClassName does not understand messageSelector`

where `ClassName` mentions the class of the receiver and `messageSelector` is the selector of the erroneously-sent message.

Note, if `nil` were an instance of `Object`, then a message sent to it in error would state

`Object does not understand messageSelector`

which is less explicit than stating that an undefined object does not understand the message. At the price of a class description, it was possible to improve on the error message.

Tests to see if an object is `nil` are handled in class `Object`, but reimplemented in `UndefinedObject`. In class `Object`, messages `isNil` and `notNil` are implemented as

**isNil**
`false`

**notNil**
`true`

In class `UndefinedObject`, messages `isNil` and `notNil` are implemented as

**isNil**
`true`

**notNil**
`false`

so that no conditional test in `Object` is required.

**Classes**
**Boolean,**
**True,** and **False**

Protocol for logical values is provided by the class `Boolean`; logical values are represented by subclasses of `Boolean`—`True` and `False`. The subclasses add no new protocol; they reimplement many messages to
have better performance than the methods in the superclass. The idea is similar to that in testing for nil in Object and UndefinedObject; true knows that it represents logical truth and false knows that it represents logical falsehood. We show the implementation of some of the controlling protocol to illustrate this idea.

The logical operations are

Boolean instance protocol

<table><tr><td>logical operations</td><td></td></tr><tr><td>&amp;aBoolean</td><td>Evaluating conjunction. Answer true if both the receiver and the argument are true.</td></tr><tr><td>| aBoolean</td><td>Evaluating disjunction. Answer true if either the receiver or the argument is true.</td></tr><tr><td>not</td><td>Negation. Answer true if the receiver is false, answer false if the receiver is true.</td></tr><tr><td>eqv: aBoolean</td><td>Answer true if the receiver is equivalent to the argument, aBoolean.</td></tr><tr><td>xor: aBoolean</td><td>Exclusive OR. Answer true if the receiver is not equivalent to aBoolean.</td></tr></table>

These conjunction and disjunction operations are "evaluating"—this means that the argument is evaluated regardless of the value of the receiver. This is in contrast to and: and or: in which the receiver determines whether to evaluate the argument.

Boolean instance protocol

<table><tr><td>controlling</td><td></td></tr><tr><td>and: alternativeBlock</td><td>Nonevaluating conjunction. If the receiver is true, answer the value of the argument; otherwise, answer false without evaluating the argument.</td></tr><tr><td>or: alternativeBlock</td><td>Nonevaluating disjunction. If the receiver is false, answer the value of the argument; otherwise, answer true without evaluating the argument.</td></tr><tr><td>ifTrue: trueAlternativeBlock ifFalse: falseAlternativeBlock</td><td>Conditional statement. If the receiver is true, answer the result of evaluating trueAlternativeBlock; otherwise answer the result of evaluating falseAlternativeBlock.</td></tr><tr><td>ifFalse: falseAlternativeBlock ifTrue: trueAlternativeBlock</td><td>Conditional statement. If the receiver is true, answer the result of evaluating trueAlternativeBlock; otherwise answer the result of evaluating falseAlternativeBlock.</td></tr><tr><td>ifTrue: trueAlternativeBlock</td><td>Conditional statement. If the receiver is true, answer the result of evaluating trueAlternativeBlock; otherwise answer nil.</td></tr><tr><td>ifFalse: falseAlternativeBlock</td><td>Conditional statement. If the receiver is false, answer the result of evaluating falseAlternativeBlock; otherwise answer nil.</td></tr></table>
The arguments to and: and or: must be blocks in order to defer evaluation. Conditional statements are provided as messages `ifTrue:ifFalse:`, `ifFalse:ifTrue:`, `ifTrue:`, and `ifFalse:`, as already specified and exemplified throughout the previous chapters. The messages are implemented in the subclasses of class Boolean so that the appropriate argument block is evaluated.

In class True, the methods are

`ifTrue: trueAlternativeBlock ifFalse: falseAlternativeBlock`

`↑trueAlternativeBlock value`

`ifFalse: falseAlternativeBlock ifTrue: trueAlternativeBlock`

`↑trueAlternativeBlock value`

`ifTrue: trueAlternativeBlock`

`↑trueAlternativeBlock value`

`ifFalse: falseAlternativeBlock`

`↑nil`

In class False, the methods are

`ifTrue: trueAlternativeBlock ifFalse: falseAlternativeBlock`

`↑falseAlternativeBlock value`

`ifFalse: falseAlternativeBlock ifTrue: trueAlternativeBlock`

`↑falseAlternativeBlock value`

`ifTrue: trueAlternativeBlock`

`↑nil`

`ifFalse: falseAlternativeBlock`

`↑falseAlternativeBlock value`

If x is 3, then

`x > 0 ifTrue: [x ← x - 1] ifFalse: [x ← x + 1]`

is interpreted as `x > 0` evaluates to true, the sole instance of class True; the method for `ifTrue:ifFalse:` is found in class True, so the block `[x ← x - 1]` is evaluated without further testing.

In this way, the message lookup mechanism provides an effective implementation of conditional control with no additional primitive operations or circular definitions.

## Additional Protocol for Class Object

Protocol for class Object, shared by all objects, was introduced in Chapter 6. Several categories of messages were not included in that early discussion. Most of these are part of Object's protocol to provide system support for message handling, dependence relationships, primitive message handling, and system primitives.
*Dependence*
*Relationships*
*Among Objects*

Information in the Smalltalk-80 system is represented by objects. The variables of objects themselves refer to objects; in this sense, objects are explicitly related or dependent on one another. Classes are related to their superclasses and metaclasses; these classes share external and internal descriptions and are thereby dependent on one another. These forms of dependency are central to the semantics of the Smalltalk-80 language. They coordinate descriptive information among objects.

An additional kind of dependency is supported in class Object. Its purpose is to coordinate activities among different objects. Specifically, its purpose is to be able to link one object, say A, to one or more other objects, say B, so B can be informed if A changes in any way. Upon being informed when A changes and the nature of the change, B can decide to take some action such as updating its own status. The concept of *change* and *update*, therefore, are integral to the support of this third kind of object dependence relationship.

The protocol in class Object is

<table><thead><tr><th colspan="2">Object instance protocol</th></tr></thead><tbody><tr><td><strong>dependents access</strong></td><td></td></tr><tr><td><code>addDependent: anObject</code></td><td>Add the argument, <code>anObject</code>, as one of the receiver's dependents.</td></tr><tr><td><code>removeDependent: anObject</code></td><td>Remove the argument, <code>anObject</code>, as one of the receiver's dependents.</td></tr><tr><td><strong>dependents</strong></td><td>Answer an <code>OrderedCollection</code> of the objects that are dependent on the receiver, that is, the objects that should be notified if the receiver changes.</td></tr><tr><td><strong>release</strong></td><td>Remove references to objects that may refer back to the receiver. This message is reimplemented by any subclass that creates references to dependents; the expression <code>super release is included in any such reimplementation.</code></td></tr><tr><td><strong>change and update</strong></td><td></td></tr><tr><td><code>changed</code></td><td>The receiver changed in some general way; inform all the dependents by sending each dependent an update: message.</td></tr><tr><td><code>changed: aParameter</code></td><td>The receiver changed; the change is denoted by the argument, <code>aParameter</code>. Usually the argument is a <code>Symbol</code> that is part of the dependent's change protocol; the default behavior is to use the receiver itself as the argument. Inform all of the dependents.</td></tr><tr><td><code>update: aParameter</code></td><td>An object on whom the receiver is dependent has changed. The receiver updates its status accordingly (the default behavior is to do nothing).</td></tr><tr><td><code>broadcast: aSymbol</code></td><td>Send the argument, <code>aSymbol</code>, as a unary message to all of the receiver's dependents.</td></tr></tbody></table>
**broadcast**: aSymbol with: anObject

Send the argument, aSymbol, as a keyword message with argument, anObject, to all of the receiver's dependents.

Take, as an example, the objects that model traffic lights. A typical traffic light at a street corner is an object with three lights, each a different color. Only one of these lights can be ON at a given moment. In this sense, the ON-OFF status of each of the three lights is dependent on the status of the other two. There are a number of ways to create this relationship. Suppose we create the class Light as follows.

<table><tr><td>class name</td><td>Light</td></tr><tr><td>superclass</td><td>Object</td></tr><tr><td>instance variable names</td><td>status</td></tr><tr><td>class methods</td><td></td></tr><tr><td>instance creation</td><td></td></tr></table>

**setOn**

↑self new setOn

**setOff**

↑self new setOff

instance methods

status

**turnOn**

self isOff

ifTrue: [status ← true. self changed]

**turnOff**

self isOn

ifTrue: [status ← false]

testing

**isOn**

↑status

**isOff**

↑status not

change and update

**update**: aLight

aLight == self ifFalse: [self turnOff]

private

**setOn**

status ← true

**setOff**

status ← false
The model is very simple. A Light is either on or off, so a status flag is kept as an instance variable; it is true if the Light is on, false if the Light is off. Whenever a Light is turned on (turnOn), it sends itself the changed message. Any other status change is not broadcast to the dependents on the assumption that a Light is turned off in reaction to turning on another Light. The default response to changed is to send all dependents the message update: self (i.e., the object that changed is the argument to the update: message). Then update: is implemented in Light to mean turn off. If the parameter is the receiver, then, of course, the update: is ignored.

The class TrafficLight is defined to set up any number of coordinated lights. The instance creation message with: takes as its argument the number of Lights to be created. Each Light is dependent on all other Lights. When the TrafficLight is demolished, the dependencies among its Lights are disconnected (the message inherited from class Object for disconnecting dependents is release; it is implemented in TrafficLight in order to broadcast the message to all Lights).

<table><tr><td>class name</td><td>TrafficLight</td></tr><tr><td>superclass</td><td>Object</td></tr><tr><td>instance variable names</td><td>lights</td></tr><tr><td>class methods</td><td></td></tr></table>

instance creation

**with: numberOfLights**

```
↑self new lights: numberOfLights
```

instance methods

operate

**turnOn: lightNumber**

```
(lights at: lightNumber) turnOn
```

initialize-release

**release**

super release.

lights do: [ :eachLight | eachLight release].

lights ← nil

private

**lights: numberOfLights**

lights ← Array new: (numberOfLights max: 1).

lights at: 1 put: Light setOn.

2 to: numberOfLights do:

```
[ :index | lights at: index put: Light setOff].
```
lights do:
[ :eachLight |
lights do:
[ :dependentLight |
eachLight ~ dependentLight
ifTrue: [eachLight addDependent: dependentLight]]

The private initialization method is lights: numberOfLights. Each light is created turned off except for the first light. Then each light is connected to all the other lights (using the message addDependent:). The simulated TrafficLight operates by some round robin, perhaps timed, sequencing through each light, turning it on. A simple example shown below creates the TrafficLight with the first light on, and then turns on each of the other lights, one at a time. A simulation of a traffic corner might include different models for controlling the lights.

trafficLight ← TrafficLight with: 3.
trafficLight turnOn: 2.
trafficLight turnOn: 3

The message turnOn: to a TrafficLight sends the message turnOn to the designated Light. If the Light is currently off, then it is set on and the message changed sent. The message changed sends update: to each dependent Light; if a dependent light is on, it is turned off.

A particularly important use of this dependency protocol is to support having multiple graphical images of an object. Each image is dependent on the object in the sense that, if the object changes, the image must be informed so that it can decide whether the change affects the displayed information. The user interface to the Smalltalk-80 system makes liberal use of this support for broadcasting notices that an object has changed; this is used to coordinate the contents of a sequence of menus of possible actions that the user can take with respect to the contents of information displayed on the screen. Menus themselves can be created by linking possible actions together, in a way similar to the way we linked together the traffic lights.

All processing in the Smalltalk-80 system is carried out by sending messages to objects. For reasons of efficiency, instances of class Message are only created when an error occurs and the message state must be stored in an accessible structure. Most messages in the system, therefore, do not take the form of directly creating an instance of Message and transmitting it to an object.

In some circumstances, it is useful to compute the message selector of a message transmission. For example, suppose that a list of possible message selectors is kept by an object and, based on a computation, one of these selectors is chosen. Suppose it is assigned as a value of a variable selector. Now we wish to transmit the message to some object, say,
to receiver. We can not simply write the expression as
receiver selector

because this means—send the object referred to by receiver the unary
message selector. We could, however, write

receiver perform: selector

The result is to transmit the value of the argument, selector, as the
message to receiver. Protocol to support this ability to send a computed
message to an object is provided in class Object. This protocol includes
methods for transmitting computed keyword as well as unary messages.

Object instance protocol

message handling

perform: aSymbol

Send the receiver the unary message indicated
by the argument, aSymbol. The argument is
the selector of the message. Report an error if
the number of arguments expected by the se-
lector is not zero.

perform: aSymbol with: anObject

Send the receiver the keyword message indi-
cated by the arguments. The first argument,
aSymbol, is the selector of the message. The
other argument, anObject, is the argument of
the message to be sent. Report an error if the
number of arguments expected by the selector
is not one.

perform: aSymbol with: firstObject with: secondObject

Send the receiver the keyword message indi-
cated by the arguments. The first argument,
aSymbol, is the selector of the message. The
other arguments, firstObject and secondObject,
are the arguments of the message to be sent.
Report an error if the number of arguments
expected by the selector is not two.

perform: aSymbol with: firstObject with: secondObject with: thirdObject

Send the receiver the keyword message indi-
cated by the arguments. The first argument,
aSymbol, is the selector of the message. The
other arguments, firstObject, secondObject,
and thirdObject, are the arguments of the mes-
sage to be sent. Report an error if the number
of arguments expected by the selector is not
three.

perform: selector withArguments: anArray

Send the receiver the keyword message indi-
cated by the arguments. The argument, selec-
tor, is the selector of the message. The
arguments of the message are the elements of
anArray. Report an error if the number of ar-
guments expected by the selector is not the
same as the size of anArray.

One way in which this protocol can be used is as a decoder of user com-
mands. Suppose for example that we want to model a very simple cal-
caleulator in which operands precede operators. A possible implementation
represents the calculator as having (1) the current result, which is also
the first operand, and (2) a possibly undefined second operand. Each op-
erator is a message selector understood by the result. Sending the mes-
sage clear, once, resets the operand; sending the message clear when the
operand is reset will reset the result.

<table><tr><td>class name</td><td>Calculator</td></tr><tr><td>superclass</td><td>Object</td></tr><tr><td>instance variable names</td><td>result<br/>operand</td></tr></table>

class methods

instance creation

new

↑super new initialize

instance methods

accessing

result

↑result

calculating

apply: operator

(self respondsTo: operator)
    ifFalse: [self error: 'operation not understood'].
    operand isNil
    ifTrue: [result ← result perform: operator]
    ifFalse: [result ← result perform: operator with: operand]

clear

operand isNil
    ifTrue: [result ← 0]
    ifFalse: [operand ← nil]

operand: aNumber

operand ← aNumber

private

initialize

result ← 0

An example illustrates the use of the class Calculator.

hp ← Calculator new

Create hp as a Calculator. The instance variables are initialized with result 0 and operand nil.
hp operand: 3

Imagine the user has pressed the key labeled 3 and set the operand.

hp apply: # +

The user selects addition. The method for apply determines that the op-
erator is understood and that the operand is not nil; therefore, the re-
sult is set by the expression

result perform: operator with: operand

which is equivalent to

$0 + 3$

The method sets result to 3; operand remains 3 so that

hp apply: # +

again adds 3, so the result is now 6.

hp operand: 1.

hp apply: # -.

hp clear.

hp apply: # squared

The result was 6, subtract 1, and compute the square; result is now 25.

## System Primitive Messages

There are a number of messages specified in class Object whose purpose is to support the needs of the overall system implementation. They are categorized as system primitives. These are messages that provide direct access to the state of an instance and, to some extent, violate the principle that each object has sovereign control over storing values into its variables. However, this access is needed by the language interpreter. It is useful in providing class description/development utilities for the programming environment. Examples of these messages are instVarAt: anInteger and instVarAt: anInteger put: anObject which retrieve and store the values of named instance variables, respectively.

### Object instance protocol

* system primitives

* become: otherObject

Swap the instance pointers of the receiver and the argument, otherObject. All variables in the entire system that pointed to the receiver
Additional Protocol for Class Object

will now point to the argument and vice versa. Report an error if either object is a `SmallInteger`.

**instVarAt: index**
Answer a named variable in the receiver. The numbering of the variables corresponds to the order in which the named instance variables were defined.

**instVarAt: index put: value**
Store the argument, value, into a named variable in the receiver. The number of variables corresponds to the order in which the named instance variables were defined. Answer value.

**nextInstance**
Answer the next instance after the receiver in the enumeration of all instances of this class. Answer nil if all instances have been enumerated.

**numberOfPointers**
Answer the number of objects to which the receiver refers.

**refct**
Answer the number of object pointers in the system that point at the receiver. Answer 0 if the receiver is a `SmallInteger`.

Probably the most unusual and effective of the system primitive messages is the message become: `otherObject`. The response to this message is to swap the instance pointer of the receiver with that of the argument, `otherObject`. An example of the use of this message is found in the implementation of the message grow in several of the collection classes. The message grow is sent when the number of elements that can be stored in a (fixed-length) collection have to be increased without copying the collection; copying is undesirable because all shared references to the collection must be preserved. Thus a new collection is created, its elements stored, and then the original collection transforms into (becomes) the new one. All pointers to the original collection are replaced by pointers to the new one.

The following is the method for grow as specified in class `SequenceableCollection`.

**grow**

| newCollection |
newCollection ← self species new: self size + self growSize.
newCollection replaceFrom: 1 to: self size with: self.
tself become: newCollection

**growSize**

↑ 10

Subclasses can redefine the response to the message `growSize` in order to specify alternative numbers of elements by which to expand.
<figure><img src="image_123.png" /></figure>
<figure><img src="image_124.png" /></figure>

15

Multiple Independent
Processes

Processes

Scheduling

Priorities

Semaphores

Mutual Exclusion

Resource Sharing

Hardware Interrupts

Class SharedQueue

Class Delay
Object

Magnitude

Character

Date

Time

Number

Float

Fraction

Integer

LargeNegательInteger

LargePositiveInteger

SmallInteger

LookupKey

Association

Link

Process

Collection

SequenceableCollection

LinkedList

Semaphore

ArrayedCollection

Array

Bitmap

DisplayBitmap

RunArray

String

Symbol

Text

ByteArray

Interval

OrderedCollection

SortedCollection

Bag

MappedCollection

Set

Dictionary

IdentityDictionary

Stream

PositionableStream

ReadStream

WriteStream

ReadWriteStream

ExternalStream

FileStream

Random

File

FileDirectory

FilePage

UndefinedObject

Boolean

False

True

ProcessorScheduler

Delay

SharedQueue

Behavior

ClassDescription

Class

MetaClass

Point

Rectangle

BitBit

CharacterScanner

Pen

DisplayObject

DisplayMedium

Form

Cursor

DisplayScreen

InfiniteForm

OpaqueForm

Path

Arc

Circle

Curve

Line

LinearFit

Spline
The Smalltalk-80 system provides support for multiple independent processes with three classes named Process, ProcessorScheduler, and Semaphore. A Process represents a sequence of actions that can be carried out independently of the actions represented by other Processes. A ProcessorScheduler schedules the use of the Smalltalk-80 virtual machine that actually carries out the actions represented by the Processes in the system. There may be many Processes whose actions are ready to be carried out and ProcessorScheduler determines which of these the virtual machine will carry out at any particular time. A Semaphore allows otherwise independent processes to synchronize their actions with each other. Semaphores provide a simple form of synchronous communication that can be used to create more complicated synchronized interactions. Semaphores also provide synchronous communication with asynchronous hardware devices such as the user input devices and realtime clock.

Semaphores are often not the most useful synchronization mechanism. Instances of SharedQueue and Delay use Semaphores to satisfy the two most common needs for synchronization. A SharedQueue provides safe transfer of objects between independent processes and a Delay allows a process to be synchronized with the real time clock.

## Processes

A *process* is a sequence of actions described by expressions and performed by the Smalltalk-80 virtual machine. Several of the processes in the system monitor asynchronous hardware devices. For example, there are processes monitoring the keyboard, the pointing device, and the realtime clock. There is also a process monitoring the available memory in the system. The most important process to the user is the one that performs the actions directly specified by the user, for example, editing text, graphics, or class definitions. This user interface process must communicate with the processes monitoring the keyboard and pointing device to find out what the user is doing. Processes might be added that update a clock or a view of a user-defined object.

A new process can be created by sending the unary message fork to a block. For example, the following expression creates a new process to display three clocks named EasternTime, MountainTime, and PacificTime on the screen.

*[EasternTime display. MountainTime display. PacificTime display] fork*
The actions that make up the new process are described by the block's expressions. The message fork has the same effect on these expressions as does the message value, but it differs in the way the result of the message is returned. When a block receives value, it waits to return until all of its expressions have been executed. For example, the following expression does not produce a value until all three clocks have been completely displayed.

[EasternTime display.
MountainTime display.
PacificTime display] value

The value returned from sending a block value is the value of the last expression in the block. When a block receives fork, it returns immediately, usually before its expressions have been executed. This allows the expressions following the fork message to be executed independently of the expressions in the block. For example, the following two expressions would result in the contents of the collection nameList being sorted independently of the three clocks being displayed.

[EasternTime display.
MountainTime display.
PacificTime display] fork.
alphabeticalList = nameList sort

The entire collection may be sorted before any of the clocks are displayed or all of the clocks may be displayed before the collection begins sorting. The occurrence of either one of these extreme cases or an intermediate case in which some sorting and some clock display are interspersed is determined by the way that display and sort are written. The two processes, the one that sends the messages fork and sort, and the one that sends display, are executed independently. Since a block's expressions may not have been evaluated when it returns from fork, the value of fork must be independent of the value of the block's expressions. A block returns itself as the value of fork.

Each process in the system is represented by an instance of class Process. A block's response to fork is to create a new instance of Process and schedule the processor to execute the expressions it contains. Blocks also respond to the message newProcess by creating and returning a new instance of Process, but the virtual machine is not scheduled to execute its expressions. This is useful because, unlike fork, it provides a reference to the Process itself. A Process created by newProcess is called suspended since its expressions are not being executed. For example, the following expression creates two new Processes but does not result in either display or sort being sent.
clockDisplayProcess → [ EasternTime display ] newProcess.
sortingProcess → [ alphabeticalList → nameList sort ] newProcess

The actions represented by one of these suspended Processes can actually be carried out by sending the Process the message resume. The following two expressions would result in display being sent to EasternTime and sort being sent to nameList.

clockDisplayProcess resume.
sortingProcess resume

Since display and sort would be sent from different Processes, their execution may be interleaved. Another example of the use of resume is the implementation of fork in BlockContext.

### fork

self newProcess resume

A complementary message, suspend, returns a Process to the suspended state in which the processor is no longer executing its expressions. The message terminate prevents a Process from ever running again, whether it was suspended or not.

Process instance protocol

<table><tr><td>changing process state</td><td></td></tr><tr><td>resume</td><td>Allow the receiver to be advanced.</td></tr><tr><td>suspend</td><td>Stop the advancement of the receiver in such a way that it can resume its progress later (by sending it the message resume).</td></tr><tr><td>terminate</td><td>Stop the advancement of the receiver forever.</td></tr></table>

Blocks also understand a message with selector newProcessWith: that creates and returns a new Process supplying values for block arguments. The argument of newProcessWith: is an Array whose elements are used as the values of the block arguments. The size of the Array should be equal to the number of block arguments the receiver takes. For example,

displayProcess → [ :clock | clock display ]
newProcessWith: (Array with: MountainTime)

The protocol of BlockContext that allows new Processes to be created is shown on the following page.
BlockContext instance protocol

scheduling

fork

Create and schedule a new Process for the execution of the expressions the receiver contains.

newProcess

Answer a new suspended Process for the execution of the expressions the receiver contains. The new Process is not scheduled.

newProcessWith: argumentArray

Answer a new suspended Process for the execution of the expressions the receiver contains supplying the elements of argumentArray as the values of the receiver's block arguments.

The Smalltalk-80 virtual machine has only one processor capable of carrying out the sequence of actions a Process represents. So when a Process receives the message resume, its actions may not be carried out immediately. The Process whose actions are currently being carried out is called *active*. Whenever the active Process receives the message suspend or terminate, a new active Process is chosen from those that have received resume. The single instance of class ProcessorScheduler keeps track of all of the Processes that have received resume. This instance of ProcessorScheduler has the global name Processor. The active Process can be found by sending Processor the message activeProcess. For example, the active Process can be terminated by the expression

Processor activeProcess terminate

This will be the last expression executed in that Process. Any expressions following it in a method would never be executed. Processor will also terminate the active Process in response to the message terminateActive.

Processor terminateActive

Priorities

Ordinarily, Processes are scheduled for the use of the processor on a simple first-come first-served basis. Whenever the active Process receives suspend or terminate, the Process that has been waiting the longest will become the new active Process. In order to provide more control of when a Process will run, Processor uses a very simple priority mechanism. There are a fixed number of priority levels numbered by ascending integers. A Process with a higher priority will gain the use of the processor before a Process with a lower priority, independent of the order of their requests. When a Process is created (with either fork or newProcess), it will receive the same priority as the Process that
created it. The priority of a Process can be changed by sending it the message priority: with the priority as an argument. Or the priority of a Process can be specified when it is forked by using the message forkAt: with the priority as an argument. For example, consider the following expressions executed in a Process at priority 4.

wordProcess → [['now' displayAt: 50@100] forkAt: 6.
['is' displayAt: 100@100] forkAt: 5.
'the' displayAt: 150@100]
newProcess.

wordProcess priority: 7.

'time' displayAt: 200@100.

wordProcess resume.

'for' displayAt: 250@100

The sequence of displays on the screen would be as follows.

<table><thead><tr><th></th><th></th><th></th><th>time</th></tr></thead><tbody><tr><td>now</td><td></td><td>the</td><td>time</td></tr><tr><td>now</td><td>is</td><td>the</td><td>time</td></tr><tr><td>now</td><td>is</td><td>the</td><td>time</td></tr></tbody></table>

Priorities are manipulated with a message to Processes and a message to BlockContexts.

### Process instance protocol

accessing

priority: anInteger Set the receiver's priority to be anInteger.

### BlockContext instance protocol

scheduling

forkAt: priority Create a new process for the execution of the expressions the receiver contains. Schedule the new process at the priority level priority.

The methods in the Smalltalk-80 system do not actually specify priorities with literal integers. The appropriate priority to use is always obtained by sending a message to Processor. The messages used to obtain priorities are shown in the protocol for class ProcessorScheduler.

One other message to Processor allows other Processes with the same priority as the active Process to gain access to the processor. The ProcessorScheduler responds to the message yield by suspending the active Process and placing it on the end of the list of Processes waiting at its priority. The first Process on the list then becomes the active Pro-
If there are no other Processes at the same priority, yield has no effect.

ProcessorScheduler instance protocol

<table><tr><td>accessing</td><td></td></tr><tr><td>activePriority</td><td>Answer the priority of the currently running process.</td></tr><tr><td>activeProcess</td><td>Answer the currently running process.</td></tr><tr><td>process state change</td><td></td></tr><tr><td>terminateActive</td><td>Terminate the currently running process.</td></tr><tr><td>yield</td><td>Give other processes at the priority of the currently running process a chance to run.</td></tr><tr><td>priority names</td><td></td></tr><tr><td>highIOPriority</td><td>Answer the priority at which the most time critical input/output processes should run.</td></tr><tr><td>lowIOPriority</td><td>Answer the priority at which most input/output processes should run.</td></tr><tr><td>systemBackgroundPriority</td><td>Answer the priority at which system background processes should run.</td></tr><tr><td>timingPriority</td><td>Answer the priority at which the system processes keeping track of real time should run.</td></tr><tr><td>userBackgroundPriority</td><td>Answer the priority at which background processes created by the user should run.</td></tr><tr><td>userInterruptPriority</td><td>Answer the priority at which processes created by the user and desiring immediate service should run.</td></tr><tr><td>userSchedulingPriority</td><td>Answer the priority at which the user interface processes should run.</td></tr></table>

The messages to ProcessorScheduler requesting priorities were listed in alphabetical order above since this is the standard for protocol descriptions. The same messages are listed below from highest priority to lowest priority along with some examples of Processes that might have that priority.

<table><tr><td>timingPriority</td><td>The Process monitoring the real time clock (see description of class Wakeup later in this chapter).</td></tr><tr><td>highIOPriority</td><td>The Process monitoring the local network communication device.</td></tr><tr><td>lowIOPriority</td><td>The Process monitoring the user input devices and the Process distributing packets from the local network.</td></tr><tr><td>userInterruptPriority</td><td>Any Process forked by the user interface that should be executed immediately.</td></tr><tr><td>userSchedulingPriority</td><td>The Process performing actions specified through the user interface (editing, viewing, programming, and debugging).</td></tr></table>
userBackgroundPriority Any Process forked by the user interface that should be executed only when nothing else is happening.

systemBackgroundPriority A system Process that should be executed when nothing else is happening.

## Semaphores

The sequence of actions represented by a Process is carried out asynchronously with the actions represented by other Processes. The function of one Process is independent of the function of another. This is appropriate for Processes that never need to interact. For example, the two Processes shown below that display clocks and sort a collection probably do not need to interact with each other at all.

* [EasternTime display.]
* MountainTime display.
* PacificTime display ] fork.
* alphabeticalList ← nameList sort

However, some Processes that are substantially independent must interact occasionally. The actions of these loosely dependent Processes must be synchronized while they interact. Instances of Semaphore provide a simple form of synchronized communication between otherwise independent Processes. A Semaphore provides for the synchronized communication of a simple (~1 bit of information) signal from one Process to another. A Semaphore provides a nonbusy wait for a Process that attempts to consume a signal that has not been produced yet. Semaphores are the only safe mechanism provided for interaction between Processes. Any other mechanisms for interaction should use Semaphores to insure their synchronization.

Communication with a Semaphore is initiated in one Process by sending it the message signal. On the other end of the communication, another Process waits to receive the simple communication by sending wait to the same Semaphore. It does not matter in which order the two messages are sent, the Process waiting for a signal will not proceed until one is sent. A Semaphore will only return from as many wait messages as it has received signal messages. If a signal and two waits are sent to a Semaphore, it will not return from one of the wait messages. When a Semaphore receives a wait message for which no corresponding signal was sent, it suspends the process from which the wait was sent.
Semaphore instance protocol

communication

signal

wait

Send a signal through the receiver. If one or more Processes have been suspended trying to receive a signal, allow the one that has been waiting the longest to proceed. If no Process is waiting, remember the excess signal.

The active Process must receive a signal through the receiver before proceeding. If no signal has been sent, the active Process will be suspended until one is sent.

The processes that have been suspended will be resumed in the same order in which they were suspended. A Process's priority is only taken into account by Processor when scheduling it for the use of the processor. Each Process waiting for a Semaphore will be resumed on a first-come first-served basis, independent of its priority. A Semaphore allows a Process to wait for a signal that has not been sent without using processor capacity. The Semaphore does not return from wait until signal has been sent. One of the main advantages of creating an independent process for a particular activity is that, if the process requires something that is not available, other processes can proceed while the first process waits for it to become available. Examples of things that a process may require and that may or may not be available are hardware devices, user events (keystrokes or pointing device movements), and shared data structures. A specific time of day can also be thought of as something that might be required for a process to proceed.

## Mutual Exclusion

Semaphores can be used to ensure mutually exclusive use of certain facilities by separate Processes. For example, a Semaphore might be used to provide a data structure that can be safely accessed by separate Processes. The following definition of a simple first-in first-out data structure does not have any provision for mutual exclusion.

<table><tr><td>class name</td><td>SimpleQueue</td></tr><tr><td>superclass</td><td>Object</td></tr><tr><td>instance variable names</td><td>contentsArray<br/>readPosition<br/>writePosition</td></tr></table>

class methods

instance creation

new

↑self new: 10

new: size

↑super new init: size
instance methods

accessing

**next**

| value |
readPosition = writePosition
    ifTrue: [self error: 'empty queue']
    ifFalse: [value ← contentsArray at: readPosition.
               contentsArray at: readPosition put: nil.
               readPosition ← readPosition + 1.
               ↑value]

**nextPut: value**

writePosition > contentsArray size
    ifTrue: [self makeRoomForWrite].
contentsArray at: writePosition put: value.
writePosition ← writePosition + 1.
↑value

**size**

↑writePosition - readPosition

testing

****

↑writePosition = readPosition

private

**init: size**

contentsArray ← Array new: size.

readPosition ← 1.

writePosition ← 1

**makeRoomForWrite**

| contentsSize |
readPosition = 1
    ifTrue: [contentsArray grow]
    ifFalse:
        [contentsSize ← writePosition − readPosition.
         1 to: contentsSize do:
             [ :index |
                 contentsArray
                 at: index
                 put: (contentsArray at: index + readPosition − 1)].
             readPosition ← 1.
             writePosition ← contentsSize + 1]

A SimpleQueue remembers its contents in an Array named
contentsArray and maintains two indices into the contentsArray named
`readPosition` and `writePosition`. New contents are added at `writePosition` and removed at `readPosition`. The private message `makeRoomForWrite` is sent when there is no room at the end of `contentsArray` for remembering a new object. If `contentsArray` is completely full, its size is increased. Otherwise, the contents are moved to the first of `contentsArray`.

The problem with sending to a `SimpleQueue` from different Processes is that more than one Process at a time may be executing the method for next or `nextPut()`. Suppose a `SimpleQueue` were sent the message next from one Process, and had just executed the expression

`value -> contentsArray at: readPosition`

when a higher priority Process woke up and sent another next message to the same `SimpleQueue`. Since `readPosition` has not been incremented, the second execution of the expression above will bind the same object to `value`. The higher priority Process will remove the reference to the object from `contentsArray`, increment the `readPosition` and return the object it removed. When the lower priority Process gets control back, `readPosition` has been incremented so it removes the reference to the next object from `contentsArray`. This object should have been the value of one of the next messages, but it is discarded and both next messages return the same object.

To ensure mutual exclusion, each Process must wait for the same Semaphore before using a resource and then signal the Semaphore when it is finished. The following subclass of `SimpleQueue` provides mutual exclusion so that its instances can be used from separate Processes.

<table><tr><td>class name</td><td>SimpleSharedQueue</td></tr><tr><td>superclass</td><td>SimpleQueue</td></tr><tr><td>instance variable names</td><td>accessProtect</td></tr><tr><td>instance methods</td><td></td></tr></table>

accessing

next

| value |
accessProtect wait.
value -> super next.
accessProtect signal.
↑value

nextPut: value

accessProtect wait.
super nextPut: value.
accessProtect signal.
↑value
private

**init: size**

super init: size.

accessProtect ← Semaphore new.

accessProtect signal

Since mutual exclusion is a common use of Semaphores, they include a message for it. The selector of this message is critical: The implementation of critical: is as follows.

**critical: aBlock**

| value |

self wait.

value ← aBlock value.

self signal.

tvalue

A Semaphore used for mutual exclusion must start out with one excess signal so the first Process may enter the critical section. Class Semaphore provides a special initialization message, forMutualExclusion, that signals the new instance once.

Semaphore instance protocol

mutual exclusion

critical: aBlock

Execute aBlock when no other critical blocks are executing.

Semaphore class protocol

instance creation

forMutualExclusion

Answer a new Semaphore with one excess signal.

The implementation of SimpleSharedQueue could be changed to read as follows.

class name

SimpleSharedQueue

superclass

SimpleQueue

instance variable names

accessProtect

instance methods

accessing

**next**

| value |

accessProtect critical: [ value ← super next ].

tvalue

**nextPut: value**

accessProtect critical: [ super nextPut: value ].

tvalue
private

**init: size**

super init: size.

accessProtect ← Semaphore forMutualExclusion

## Resource Sharing

In order for two Processes to share a resource, mutually exclusive access to it is not enough. The Processes must also be able to communicate about the availability of the resource. SimpleSharedQueue will not get confused by simultaneous accesses, but if an attempt is made to remove an object from an empty SimpleSharedQueue, an error occurs. In an environment with asynchronous Processes, it is inconvenient to guarantee that attempts to remove objects (by sending next) will be made only after they have been added (by sending nextPut). Therefore, Semaphores are also used to signal the availability of shared resources. A Semaphore representing a resource is signalled after each unit of the resource is made available and waited for before consuming each unit. Therefore, if an attempt is made to consume a resource before it has been produced, the consumer simply waits.

Class SafeSharedQueue is an example of how Semaphores can be used to communicate about the availability of resources. SafeSharedQueue is similar to SimpleSharedQueue, but it uses another Semaphore named valueAvailable to represent the availability of the contents of the queue. SafeSharedQueue is not in the Smalltalk-80 system, it is described here only as an example. SharedQueue is the class that is actually used to communicate between processes in the system. SharedQueue provides functionality similar to SafeSharedQueue's. The protocol specification for SharedQueue will be given later in this chapter.

<table><tr><td>class name</td><td>SafeSharedQueue</td></tr><tr><td>superclass</td><td>SimpleQueue</td></tr><tr><td>instance variable names</td><td>accessProtect<br>valueAvailable</td></tr><tr><td>instance methods</td><td></td></tr></table>

accessing

**next**

| value |

valueAvailable wait.

accessProtect critical: [ value ← super next ].

↑value

**nextPut: value**

accessProtect critical: [ super nextPut: value ].

valueAvailable signal.

↑value
private

**init: size**

super init: size.

accessProtect ← Semaphore forMutualExclusion.

valueAvailable ← Semaphore new

Hardware
Interrupts

Instances of Semaphore are also used to communicate between hard-
ware devices and Processes. In this capacity, they take the place of in-
terrupts as a means of communicating about the changes of state that
hardware devices go through. The Smalltalk-80 virtual machine is spec-
ified to signal Semaphores on three conditions.

* user event: a key has been pressed on the keyboard, a button has been pressed on the pointing device, or the pointing device has moved.

* timeout: a specific value of the millisecond clock has been reached.

* low space: available object memory has fallen below certain limits.

These three Semaphores correspond to three Processes monitoring user
events, the millisecond clock and memory utilization. Each monitoring
Process sends wait to the appropriate Semaphore suspending itself until
something of interest happens. Whenever the Semaphore is signalled,
the Process will resume. The virtual machine is notified about these
three types of monitoring by primitive methods. For example, the
timeout signal can be requested by a primitive method associated with
the message signal:atTime: to Processor.

Class Wakeup is an example of how one of these Semaphores can be
used. Wakeup provides an alarm clock service to Processes by monitor-
ing the millisecond clock. Wakeup is not in the Smalltalk-80 system; it
is described here only as an example. Delay is the class that actually
monitors the millisecond clock in the Smalltalk-80 system. Delay pro-
vides functionality similar to Wakeup's. The protocol specification for
Delay will be given later in this chapter.

Wakeup provides a message that suspends the sending Process for a
specified number of milliseconds. The following expression suspends its
Process for three quarters of a second.

Wakeup after: 750

When Wakeup receives an after: message, it allocates a new instance
which remembers the value of the clock at which the wakeup should
occur. The new instance contains a Semaphore on which the active Pro-
cess will be suspended until the wakeup time is reached. Wakeup keeps
all of its instances in a list sorted by their wakeup times. A Process monitors the virtual machine's millisecond clock for the earliest of these wakeup times and allows the appropriate suspended Process to proceed. This Process is created in the class method for initializeTimingProcess. The Semaphore used to monitor the clock is referred to by a class variable named TimingSemaphore. The virtual machine is informed that the clock should be monitored with the following message found in the instance method for nextWakeup.

Processor signal: TimingSemaphore atTime: resumptionTime

The list of instances waiting for resumption is referred to by a class variable named PendingWakeups. There is another Semaphore named AccessProtect that provides mutually exclusive access to PendingWakeups.

<table><tr><td>class name</td><td>Wakeup</td></tr><tr><td>superclass</td><td>Object</td></tr><tr><td>instance variable names</td><td>alarmTime<br/>alarmSemaphore</td></tr><tr><td>class variable names</td><td>PendingWakeups<br/>AccessProtect<br/>TimingSemaphore</td></tr></table>

class methods

alarm clock service

**after: millisecondCount**

(self new sleepDuration: millisecondCount)waitForWakeup

class initialization

**initialize**

TimingSemaphore ← Semaphore new.

AccessProtect ← Semaphore forMutualExclusion.

PendingWakeups ← SortedCollection new.

self initializeTimingProcess

**initializeTimingProcess**

[[true]

whileTrue:

[TimingSemaphore wait.

AccessProtect wait.

PendingWakeups removeFirst wakeup.

PendingWakeups empty

ifFalse: [PendingWakeups first nextWakeup].

AccessProtect signal]]

forkAt: Processor timingPriority
instance methods

process delay

**waitForWakeup**

AccessProtect wait.

PendingWakeups add: self.

PendingWakeups first == self

ifTrue: [self nextWakeup].

AccessProtect signal.

alarmSemaphore wait

comparison

< otherWakeup

talarmTime < otherWakeup wakeupTime

accessing

**wakeupTime**

talarmTime

private

**nextWakeup**

Processor signal: TimingSemaphore atTime: resumptionTime

**sleepDuration: millisecondCount**

alarmTime ← Time millisecondClockValue + millisecondCount.

alarmSemaphore ← Semaphore new

**wakeup**

alarmSemaphore signal

## Class SharedQueue

Class SharedQueue is the system class whose instances provide safe communication of objects between Processes. Both its protocol and its implementation are similar to the SafeSharedQueue example shown earlier in this chapter.

### SharedQueue instance protocol

accessing

next

Answer with the first object added to the receiver that has not yet been removed. If the receiver is empty, suspend the active Process until an object is added to it.

nextPut: value

Add value to the contents of the receiver. If a Process has been suspended waiting for an object, allow it to proceed.
## Class Delay

A Delay allows a Process to be suspended for a specified amount of time. A Delay is created by specifying how long it will suspend the active Process.

halfMinuteDelay ← Delay forSeconds: 30.

shortDelay ← Delay forMilliseconds: 50

Simply creating a Delay has no effect on the progress of the active Process. It is in response to the message wait that a Delay suspends the active Process. The following expressions would both suspend the active Process for 30 seconds.

halfMinuteDelay wait.

(Delay forSeconds: 30) wait

### Delay class protocol

#### instance creation

forMilliseconds: millisecondCount Answer with a new instance that will suspend the active Process for millisecondCount milliseconds when sent the message wait.

forSeconds: secondCount Answer with a new instance that will suspend the active Process for secondCount seconds when sent the message wait.

untilMilliseconds: millisecondCount Answer with a new instance that will suspend the active Process until the millisecond clock reaches the value millisecondCount.

#### general inquiries

millisecondClockValue Answer with the current value of the millisecond clock.

### Delay instance protocol

#### accessing

resumptionTime Answer with the value of the millisecond clock at which the delayed Process will be resumed.

#### process delay

wait Suspend the active Process until the millisecond clock reaches the appropriate value.

A trivial clock can be implemented with the following expression.

[[true] whileTrue:

[Time now printString displayAt: 100@100.

(Delay forSeconds: 1) wait]] fork

The current time would be displayed on the screen once a second.
16

Protocol for Classes

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

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

Class Behavior

Class ClassDescription

Class Metaclass

Class Class
## Object

### Magnitude

Character

Date

Time

### Number

Float

Fraction

Integer

LargeNegativeInteger

LargePositiveInteger

SmallInteger

### LookupKey

Association

Link

Process

Collection

### SequenceableCollection

LinkedList

Semaphore

### ArrayedCollection

Array

### Bitmap

DisplayBitmap

### RunArray

String

Symbol

Text

ByteArray

### Interval

### OrderedCollection

SortedCollection

Bag

MappedCollection

Set

### Dictionary

IdentityDictionary

### Stream

PositionableStream

ReadStream

WriteStream

ReadWriteStream

ExternalStream

FileStream

Random

File

FileDirectory

FilePage

UndefinedObject

Boolean

False

True

### ProcessorScheduler

Delay

SharedQueue

### Behavior

ClassDescription

Class

MetaClass

Point

Rectangle

BitBit

CharacterScanner

Pen

### DisplayObject

DisplayMedium

Form

Cursor

DisplayScreen

InfiniteForm

OpaqueForm

Path

Arc

Circle

Curve

Line

LinearFit

Spline
We have now introduced the protocol for most of the classes that describe the basic components of the Smalltalk-80 system. One notable exception is the protocol for the classes themselves. Four classes—Behavior, ClassDescription, Metaclass, and Class—interact to provide the facilities needed to describe new classes. Creating a new class involves compiling methods and specifying names for instance variables, class variables, pool variables, and the class itself.

Chapters 3, 4, and 5 introduced the basic concepts represented by these classes. To summarize from that discussion, the Smalltalk-80 programmer specifies a new class by creating a subclass of another class. For example, class Collection is a subclass of Object; class Array is a subclass of ArrayedCollection (whose superclass chain terminates with Object).

1. Every class is ultimately a subclass of class Object, except for Object itself, which has no superclass. In particular, Class is a subclass of ClassDescription, which is a subclass of Behavior which is a subclass of Object.

There are two kinds of objects in the system, ones that can create instances of themselves (classes) and ones that can not.

2. Every object is an instance of a class.

Each class is itself an instance of a class. We call the class of a class, its metaclass.

3. Every class is an instance of a metaclass.

Metaclasses are not referenced by class names as are other classes. Instead, they are referred to by a message expression sending the unary message class to the instance of the metaclass. For example, the metaclass of Collection is referred to as Collection class; the metaclass of Class is referred to as Class class.

In the Smalltalk-80 system, a metaclass is created automatically whenever a new class is created. A metaclass has only one instance. The messages categorized as "class methods" in the class descriptions are found in the metaclass of the class. This follows from the way in which methods are found; when a message is sent to an object, the search for the corresponding method begins in the class of the object. When a message is sent to Dictionary, for example, the search begins in the metaclass of Dictionary. If the method is not found in the metaclass, then the search proceeds to the superclass of the metaclass. In this case, the superclass is Set class, the metaclass for Dictionary's superclass. If necessary, the search follows the superclass chain to Object class.
In the diagrams in this chapter, all arrows with solid lines denote a subclass relationship; arrows with dashed lines an instance relationship. A ---> B means A is an instance of B. Solid gray lines indicate the class hierarchy; solid black lines indicate the metaclass hierarchy.

<figure><img src="image_127.png" /><figcaption>Figure 16.1</figcaption></figure>

Since the superclass chain of all objects ends at Object as shown in Figure 16.1, and Object has no superclass, the superclass of Object's metaclass is not determined by the rule of maintaining a parallel hierarchy. It is at this point that Class is found. The superclass of Object class is Class.

4. All metaclasses are (ultimately) subclasses of Class (Figure 16.2).

<figure><img src="image_128.png" /><figcaption>Figure 16.2</figcaption></figure>

Since metaclasses are objects, they too must be instances of a class. Every metaclass is an instance of Metaclass. Metaclass itself is an instance of a metaclass. This is a point of circularity in the system—the metaclass of Metaclass must be an instance of Metaclass.

5. Every metaclass is an instance of Metaclass (Figure 16.3).

Figure 16.4 shows the relationships among Class, ClassDescription, Behavior, and Object, and their respective metaclasses. The class hierarchy follows a chain to Object, and the metaclass hierarchy follows a chain through Object class to Class and on to Object. While the methods of
<figure><img src="image_129.png" /></figure>

Object support the behavior common to all objects, the methods of Class and Metaclass support the behavior common to all classes.

6. The methods of Class and its superclasses support the behavior common to those objects that are classes.

7. The methods of instances of Metaclass add the behavior specific to particular classes.

The correspondence between the class and metaclass hierarchies is shown in Figure 16.5, in which the part of the number hierarchy and the behavior hierarchy of the last two figures are combined.

<figure><img src="image_130.png" /></figure>
<figure><img src="image_131.png" /></figure>

Class Behavior

Class Behavior defines the minimum state necessary for objects that have instances. In particular, Behavior defines the state used by the Smalltalk-80 interpreter. It provides the basic interface to the compiler. The state described by Behavior includes a class hierarchy link, a method dictionary, and a description of instances in terms of the number and the representation of their variables.

The message protocol for class Behavior will be described in four categories—*creating*, *accessing*, *testing*, and *enumerating*. These categories and their subcategories, as outlined below, provide a model for thinking about the functionality of classes in the Smalltalk-80 system.
## Outline of Protocol for All Classes

### creating

* creating a method dictionary

* creating instances

* creating a class hierarchy

### accessing

* accessing the contents of the method dictionary

* accessing instances and variables: instance, class, and pool

* accessing the class hierarchy

### testing

* testing the contents of the method dictionary

* testing the form of the instances

* testing the class hierarchy

### enumerating

* enumerating subclasses and instances

□ **Behavior's Creating Protocol** The methods in a class description are stored in a dictionary we refer to as the *method dictionary*. It is also sometimes called a message dictionary. The keys in this dictionary are message selectors; the values are the compiled form of methods (instances of CompiledMethod). The protocol for creating the method dictionary supports compiling methods as well as adding the association between a selector and a compiled method. It also supports accessing both the compiled and noncompiled (source) versions of the method.

### Behavior instance protocol

#### creating method dictionary

<table><tr><td>methodDictionary: aDictionary</td><td>Store the argument, aDictionary, as the method dictionary of the receiver.</td></tr><tr><td>addSelector: selector withMethod: compiledMethod</td><td>Add the message selector, selector, with the corresponding compiled method, compiled-Method, to the receiver's method dictionary.</td></tr><tr><td>removeSelector: selector</td><td>Remove the argument, selector (which is a Symbol representing a message selector), from the receiver's method dictionary. If the selector is not in the method dictionary, report an error.</td></tr><tr><td>compile: code</td><td>The argument, code, is either a String or an object that converts to a String or it is a PositionableStream accessing an object that is or converts to a String. Compile code as the source code in the context of the receiver's variables. Report an error if the code can not be compiled.</td></tr></table>
<table><tr><td>compile: code notifying: requestor</td><td>Compile the argument, code, and enter the result in the receiver's method dictionary. If an error occurs, send an appropriate message to the argument, requestor.</td></tr><tr><td>recompile: selector</td><td>Compile the method associated with the message selector, selector.</td></tr><tr><td>decompile: selector</td><td>Find the compiled code associated with the argument, selector, and decompile it. Answer the resulting source code as a String. If the selector is not in the method dictionary, report an error.</td></tr><tr><td>compileAll</td><td>Compile all the methods in the receiver's method dictionary.</td></tr><tr><td>compileAllSubclasses</td><td>Compile all the methods in the receiver's subclasses' method dictionaries.</td></tr></table>

Instances of classes are created by sending the message new or new. These two messages can be overridden in the method dictionary of a metaclass in order to supply special initialization behavior. The purpose of any special initialization is to guarantee that an instance is created with variables that are themselves appropriate instances. We have demonstrated this idea in many previous chapters. Look, for example, at the definition of class Random in Chapter 12; the method dictionary of Random class (the class methods) contains an implementation for new in which a new instance is sent the message setSeed; this initialization guarantees that the random number generation algorithm refers to a variable that is an appropriate kind of number.

Suppose a class overrides the method for new and then one of its subclasses wishes to do the same in order to avoid the behavior created by its superclass's change. The method for the first class might be

### new

```
super new setVariables
```

where the message setVariables is provided in the protocol for instances of the class. By sending the message new to the pseudo-variable super, the method for creating an instance as specified in class Behavior is evaluated; the result, the new instance, is then sent the message setVariables. In the subclass, it is not possible to utilize the message super new because this will invoke the method of the first class—precisely the method to be avoided. In order to obtain the basic method in Behavior for creating an instance, the subclass must use the expression self basicNew. The message basicNew is the primitive instance creation message that should not be reimplemented in any subclass. In Behavior, new and basicNew are identical. A similar pair for creating variable-length objects, new: and basicNew:, are also provided in the protocol of class Behavior. (Note, this technique of dual messages is also used in class Object for accessing messages such as at: and at:put:.)
Behavior instance protocol

instance creation

new

Answer an instance of the receiver with no indexed variables. Send the receiver the message new: 0 if the receiver is indexable.

basicNew

Same as new, except this method should not be overridden in a subclass.

new: anInteger

Answer an instance of the receiver with anInteger number of indexed variables. Report an error if the receiver is not indexable.

basicNew: anInteger

Same as basicNew, except this method should not be overridden in a subclass.

The protocol for creating classes includes messages for placing the class within the hierarchy of classes in the system. Since this hierarchy is linear, there is only a need to set the superclass and to add or remove subclasses.

Behavior instance protocol

creating a class hierarchy

superclass: aClass

Set the superclass of the receiver to be the argument, aClass.

addSubclass: aClass

Make the argument, aClass, be a subclass of the receiver.

removeSubclass: aClass

Remove the argument, aClass, from the subclasses of the receiver.

Although the creating protocol for Behavior makes it possible to write expressions for creating a new class description, the usual approach is to take advantage of the graphical environment in which the Smalltalk-80 language is embedded, and to provide an interface in which the user fills out graphically-presented forms to specify information about the various parts of a class.

☐ Behavior's *Accessing Protocol* The messages that access the contents of a method dictionary distinguish among the selectors in the class's locally specified method dictionary, and those in the method dictionaries of the class and each of its superclasses.

Behavior instance protocol

accessing the method dictionary

selectors

Answer a Set of all the message selectors specified in the receiver's local method dictionary.

allSelector

Answer a Set of all the message selectors that instances of the receiver can understand. This consists of all message selectors in the receiver's method dictionary and in the dictionaries of each of the receiver's superclasses.
<table><tr><td>compiledMethodAt: selector</td><td>Answer the compiled method associated with the argument, selector, a message selector in the receiver's local method dictionary. Report an error if the selector can not be found.</td></tr><tr><td>sourceCodeAt: selector</td><td>Answer a String that is the source code associated with the argument, selector, a message selector in the receiver's local method dictionary. Report an error if the selector can not be found.</td></tr><tr><td>sourceMethodAt: selector</td><td>Answer a Text for the source code associated with the argument, selector, a message selector in the receiver's local method dictionary. This Text provides boldface emphasis for the message pattern part of the method. Report an error if the selector can not be found.</td></tr></table>

An instance can have named instance variables, indexed instance variables, class variables, and dictionaries of pool variables. Again, the distinction between locally specified variables and variables inherited from superclasses is made in the accessing protocol.

Behavior instance protocol

<table><tr><td>accessing instances and variables</td><td></td></tr><tr><td>allInstances</td><td>Answer a Set of all direct instances of the receiver.</td></tr><tr><td>someInstance</td><td>Answer an existing instance of the receiver.</td></tr><tr><td>instanceCount</td><td>Answer the number of instances of the receiver that currently exist.</td></tr><tr><td>instVarNames</td><td>Answer an Array of the instance variable names specified in the receiver.</td></tr><tr><td>subclassInstVarNames</td><td>Answer a Set of the instance variable names specified in the receiver's subclasses.</td></tr><tr><td>allInstVarNames</td><td>Answer an Array of the names of the receiver's instance variables, those specified in the receiver and in all of its superclasses. The Array ordering is the order in which the variables are stored and accessed by the Smalltalk-80 interpreter.</td></tr><tr><td>classVarNames</td><td>Answer a Set of the class variable names specified locally in the receiver.</td></tr><tr><td>allClassVarNames</td><td>Answer a Set of the names of the receiver's and the receiver's superclasses' class variables.</td></tr><tr><td>sharedPools</td><td>Answer a Set of the names of the pools (dictionaries) that are specified locally in the receiver.</td></tr><tr><td>allSharedPools</td><td>Answer a Set of the names of the pools (dictionaries) that are specified in the receiver and each of its superclasses.</td></tr></table>
Thus, for example,

<table><thead><tr><td>expression</td><td>result</td></tr></thead><tbody><tr><td>OrderedCollection instVarNames</td><td>('firstIndex' 'lastIndex')</td></tr><tr><td>OrderedCollection subclassInstVarNames</td><td>Set ('sortBlock')</td></tr><tr><td>SortedCollection allInstVarNames</td><td>('firstIndex' 'lastIndex' 'sortBlock')</td></tr><tr><td>String classVarNames</td><td>Set (StringBlter)</td></tr><tr><td>String allClassVarNames</td><td>Set (StringBlter DependentsFields ErrorRecursion)</td></tr><tr><td>Text sharedPools</td><td>a Set containing one element, TextConstants, a Dictionary</td></tr></tbody></table>

The accessing protocol includes messages for obtaining collections of the superclasses and subclasses of a class. These messages distinguish between a class's immediate superclass and subclasses, and all classes in the class's superclass chain.

Behavior instance protocol

<table><tbody><tr><td>accessing class hierarchy<br/>subclasses</td><td>Answer a Set containing the receiver's immediate subclasses.</td></tr><tr><td>allSubclasses</td><td>Answer a Set of the receiver's subclasses and the receiver's descendent's subclasses.</td></tr><tr><td>withAllSubclasses</td><td>Answer a Set of the receiver, the receiver's subclasses and the receiver's descendent's subclasses.</td></tr><tr><td>superclass</td><td>Answer the receiver's immediate superclass.</td></tr><tr><td>allSuperclasses</td><td>Answer an OrderedCollection of the receiver's superclass and the receiver's ancestor's subclasses. The first element is the receiver's immediate superclass, followed by its superclass, and so on; the last element is always Object.</td></tr></tbody></table>

Thus, for example

<table><thead><tr><td>expression</td><td>result</td></tr></thead><tbody><tr><td>String superclass</td><td>ArrayedCollection</td></tr><tr><td>ArrayedCollection subclasses</td><td>Set (Array ByteArray RunArray Bitmap String Text)</td></tr></tbody></table>
<table><tr><td>ArrayedCollection<br/>allSubclasses</td><td>Set (Array ByteArray<br/>RunArray Bitmap<br/>String Text<br/>DisplayBitmap Symbol<br/>CompiledMethod )</td></tr><tr><td>ArrayedCollection<br/>withAllSubclasses</td><td>Set<br/>(ArrayedCollection<br/>Array ByteArray<br/>RunArray Bitmap<br/>String Text<br/>DisplayBitmap Symbol<br/>CompiledMethod )</td></tr><tr><td>ArrayedCollection<br/>allSuperclasses</td><td>OrderedCollection<br/>(SequenceableCollection<br/>Collection Object )</td></tr><tr><td>ArrayedCollection<br/>class allSuperclasses</td><td>OrderedCollection<br/>(SequenceableCollection<br/>class Collection class<br/>Object class Class<br/>ClassDescription<br/>Behavior Object )</td></tr></table>

☐ Behavior's Testing Protocol Testing protocol provides the messages needed to find out information about the structure of a class and the form of its instances. The structure of a class consists of its relationship to other classes, its ability to respond to messages, the class in which a message is specified, and so on.

The contents of a method dictionary can be tested to find out which class, if any, implements a particular message selector, whether a class can respond to a message, and which methods reference particular variables or literals. These messages are all useful in creating a programming environment in which the programmer can explore the structure and functionality of objects in the system.

Behavior instance protocol

<table><tr><td>testing the method dictionary<br/>hasMethods</td><td>Answer whether the receiver has any methods<br/>in its (local) method dictionary.</td></tr><tr><td>includesSelector: selector</td><td>Answer whether the message whose selector is<br/>the argument, selector, is in the local method<br/>dictionary of the receiver's class.</td></tr><tr><td>canUnderstand: selector</td><td>Answer whether the receiver can respond to<br/>the message whose selector is the argument.</td></tr></table>
The selector can be in the method dictionary of the receiver's class or any of its super-classes.

**whichClassIncludesSelector: selector**

Answer the first class on the receiver's super-class chain where the argument, selector, can be found as a message selector. Answer nil if no class includes the selector.

**whichSelectorAccess: instVarName**

Answer a Set of selectors from the receiver's local method dictionary whose methods access the argument, instVarName, as a named instance variable.

**whichSelectorReferTo: anObject**

Answer a Set of selectors whose methods access the argument, anObject.

**scopeHas: name ifTrue: aBlock**

Determine whether the variable name, name, is within the scope of the receiver, i.e., it is specified as a variable in the receiver or in one of its superclasses. If so, evaluate the argument, aBlock.

Thus, for example

<table><thead><tr><th>expression</th><th>result</th></tr></thead><tbody><tr><td>OrderedCollection<br>  includesSelector:<br>    #addFirst:</td><td>true</td></tr><tr><td>SortedCollection<br>  includesSelector: #size</td><td>false</td></tr><tr><td>SortedCollection<br>  canUnderstand: #size</td><td>true</td></tr><tr><td>SortedCollection<br>  whichClassIncludesSelector:<br>    #size</td><td>OrderedCollection</td></tr><tr><td>OrderedCollection<br>  whichSelectorAccess:<br>    #firstIndex</td><td>Set<br>(makeRoomAtFirst<br>    before: size<br>    makeRoomAtLast<br>    insert: before:<br>      remove: ifAbsent:<br>        addFirst: first<br>      removeFirst find:<br>        removeAllSuchThat:<br>          at: at:put: reverseDo:<br>            do: setIndices: )</td></tr></tbody></table>

The last example expression is useful in determining which methods must be changed if an instance variable is renamed or deleted. In addi-
tion to the messages intended for external access, the Set includes all messages implemented in support of the implementation of the external messages.

The testing protocol includes messages to a class that test how its variables are stored, whether the number of variables is fixed-length or variable-length, and the number of named instance variables.

Behavior instance protocol

testing the form of the instances

isPointers Answer whether the variables of instances of the receiver are stored as pointers (words).

isBits Answer whether the variables of instances of the receiver are stored as bits (i.e., not pointers).

isBytes Answer whether the variables of instances of the receiver are stored as bytes (8-bit integers).

isWords Answer whether the variables of instances of the receiver are stored as words.

isFixed Answer true if instances of the receiver do not have indexed instance variables; answer false otherwise.

isVariable Answer true if instances of the receiver do not have indexed instance variables; answer false otherwise.

instSize Answer the number of named instance variables of the receiver.

So we have

<table><thead><tr><th>expression</th><th>result</th></tr></thead><tbody><tr><td>LinkedList isFixed</td><td>true</td></tr><tr><td>String isBytes</td><td>true</td></tr><tr><td>Integer isBits</td><td>false</td></tr><tr><td>Float isWords</td><td>true</td></tr><tr><td>OrderedCollection isFixed</td><td>false</td></tr><tr><td>OrderedCollection instSize</td><td>2</td></tr><tr><td>oc &rarr; OrderedCollection<br>with: $a<br>with: $b<br>with: $c</td><td>OrderedCollection<br>($a $b $c)</td></tr><tr><td>oc size</td><td>3</td></tr></tbody></table>

The last four example lines show that instances of OrderedCollection are variable-length; the instance oc has three elements. In addition, instances of OrderedCollection have two named instance variables.

There are four kinds of classes in the system. Classes that have
indexed instance variables are called *variable-length* and classes that do not are called *fixed-length*. The variables of all fixed-length classes are stored as pointers (word-sized references). The variables of variable-length classes can contain pointers, bytes, or words. Since a pointer is a word-sized reference, an object that contains pointers will answer true when asked whether it contains words, but the inverse is not always the case. Initialization messages specified in *Class* and itemized in a later section support creation of each kind of class.

Behavior instance protocol

testing the class hierarchy

inheritsFrom: aClass

kindOfSubclass

Answer whether the argument, aClass, is on the receiver's superclass chain.

Answer a String that is the keyword that describes the receiver as a class: either a regular (fixed length) subclass, a variableSubclass, a variableByteSubclass, or a variableWordSubclass.

Thus

<table><thead><tr><td>expression</td><td>result</td></tr></thead><tbody><tr><td>String inheritsFrom: Collection</td><td>true</td></tr><tr><td>String kindOfSubclass</td><td>'variableByteSubclass: '</td></tr><tr><td>Array kindOfSubclass</td><td>'variableSubclass: '</td></tr><tr><td>Float kindOfSubclass</td><td>'variableWordSubclass: '</td></tr><tr><td>Integer kindOfSubclass</td><td>'subclass: '</td></tr></tbody></table>

☐ Behavior's *Enumerating Protocol* Messages specified in class Behavior also support listing out particular sets of objects associated with a class and applying each as the argument of a block. This enumeration of objects is similar to that provided in the collection classes, and consists of enumerating over all subclasses, superclasses, instances, and instances of subclasses. In addition, two messages support selecting those subclasses or superclasses for which a block evaluates to true.

Behavior instance protocol

enumerating

allSubclassesDo: aBlock

allSuperclassesDo: aBlock

allInstancesDo: aBlock

Evaluate the argument, aBlock, for each of the receiver's subclasses.

Evaluate the argument, aBlock, for each of the receiver's superclasses.

Evaluate the argument, aBlock, for each of the current instances of the receiver.
allSubinstancesDo: aBlock Evaluate the argument, aBlock, for each of the current instances of the receiver's subclasses.

selectSubclasses: aBlock Evaluate the argument, aBlock, for each of the receiver's subclasses. Collect into a Set only those subclasses for which aBlock evaluates to true. Answer the resulting Set.

selectSuperclasses: aBlock Evaluate the argument, aBlock, with each of the receiver's superclasses. Collect into a Set only those superclasses for which aBlock evaluates to true. Answer the resulting Set.

As an example, in order to understand the behavior of an instance of the collection classes, it might be useful to know which subclasses of Collection implement the adding message addFirst: With this information, the programmer can track down which method is actually evaluated when the message addFirst: is sent to a collection. The following expression collects each such class into a Set named subs.

subs ← Set new.

Collection allSubclassesDo:

[ :class |
(class includesSelector: #addFirst:)
ifTrue: [subs add: class]]

The same information is accessible from

Collection selectSubclasses:

[ :class | class includesSelector: #addFirst:]

Both create a Set of the three subclasses LinkedList, OrderedCollection, and RunArray.

The following expression returns a collection of the superclasses of SmallInteger that implement the message =.

SmallInteger selectSuperclasses:

[ :class | class includesSelector: #==]

The response is

Set (Integer Magnitude Object)

Several subclasses of Collection implement the message first. Suppose we wish to see a list of the code for each implementation. The following expressions print the code on the file whose name is 'classMethods.first'.
```
aStream
aStream -> Disk file: 'classMethods.first'.
Collection allSubclassesDo:
    [ :class |
        (class includesSelector: #first)
        ifTrue:
            [class name printOn: aStream.
             aStream cr.
             (class sourceCodeAt: #first) printOn: aStream.
             aStream cr; cr]].
    aStream close
```

The resulting contents of the file is:

```
SequenceableCollection
    'first
        self emptyCheck.
        ↑self at: 1'
OrderedCollection
    'first
        self emptyCheck.
        ↑self basicAt: firstIndex'
Interval
    'first
        ↑start'
LinkedList
    'first
        self emptyCheck.
        ↑firstLink'
```

The protocol described in the next sections is not generally used by programmers, but may be of interest to system developers. The messages described are typically accessed in the programming environment by selecting items from a menu presented in a graphically-oriented interface.

Although most of the facilities of a class are specified in the protocol of Behavior, a number of the messages can not be implemented because Behavior does not provide a complete representation for a class. In particular, Behavior does not provide a representation for instance variable names and class variable names, nor for a class name and a comment about the class.

Representations for a class name, class comment, and instance variable names are provided in ClassDescription, a subclass of Behavior. ClassDescription has two subclasses, Class and Metaclass. Class de-
scribes the representation for class variable names and pool variables. A metaclass shares the class and pool variables of its sole instance. Class adds additional protocol for adding and removing class variables and pool variables, and for creating the various kinds of subclasses. Metaclass adds an initialization message for creating a subclass of itself, that is, a message for creating a metaclass for a new class.

Class
ClassDescription

ClassDescription represents class naming, class commenting, and naming instance variables. This is reflected in additional protocol for accessing the name and comment, and for adding and removing instance variables.

ClassDescription instance protocol

accessing class description

name Answer a String that is the name of the receiver.

comment Answer a String that is the comment for the receiver.

comment: aString Set the receiver's comment to be the argument, aString.

addInstVarName: aString Add the argument, aString, as one of the receiver's instance variables.

removeInstVarName: aString Remove the argument, aString, as one of the receiver's instance variables. Report an error if aString is not found.

ClassDescription was provided as a common superclass for Class and Metaclass in order to provide further structuring to the description of a class. This helps support a general program development environment. Specifically, ClassDescription adds structure for organizing the selector/method pairs of the method dictionary. This organization is a simple categorization scheme by which the subsets of the dictionary are grouped and named, precisely the way we have been grouping and naming messages throughout the chapters of this book. ClassDescription also provides the mechanisms for storing a full class description on an external stream (a file), and the mechanisms by which any changes to the class description are logged.

The classes themselves are also grouped into system category classifications. The organization of the chapters of this part of the book parallels that of the system class categories, for example, magnitudes, numbers, collections, kernel objects, kernel classes, and kernel support. Protocol for message and class categorization includes the following messages.
ClassDescription instance protocol

organization of messages and classes

<table><tr><td>category</td><td>Answer the system organization category for the receiver.</td></tr><tr><td>category: aString</td><td>Categorize the receiver under the system category, aString, removing the receiver from any previous category.</td></tr><tr><td>removeCategory: aString</td><td>Remove each of the messages categorized under the name aString and then remove the category itself.</td></tr><tr><td>whichCategoryIncludesSelector: selector</td><td>Answer the category of the argument, selector, in the organization of the receiver's method dictionary, or answer nil if the selector can not be found.</td></tr></table>

Given a categorization of the messages, ClassDescription is able to support a set of messages for copying messages from one method dictionary to another, retaining or changing the category name. Messages to support copying consists of

copy: selector from: aClass

copy: selector from: aClass classified: categoryName

copyAll: arrayOf selectors from: class

copyAll: arrayOf selectors from: class classified: categoryName

copyAllCategoriesFrom: aClass

copyCategory: categoryName from: aClass

copyCategory: categoryName
from: aClass
classified: newCategoryName

The categorization scheme has an impact on protocol for compiling since a compiled method must be placed in a particular category. Two messages are provided: compile: code classified: categoryName and compile: code classified: categoryName notifying: requestor.

We also note, for the next example, that Behavior supports special printing protocol so that arguments to the compiling messages can be computed. These are

Behavior instance protocol

printing

classVariableString
Answer a String that contains the names of each class variable in the receiver's variable declaration.

instanceVariableString
Answer a String that contains the names of each instance variable in the receiver's variable declaration.
sharedVariableString

Answer a String that contains the names of each pool dictionary in the receiver's variable declaration.

Take as an example the creation of a class named AuditTrail. This class should be just like LinkedList, except that removing elements should not be supported. Therefore, the class can be created by copying the accessing, testing, adding, and enumerating protocol of LinkedList. We assume that the elements of an AuditTrail are instances of a subclass of Link that supports storing the audit information. First, let's create the class. We assume that we do not know internal information about LinkedList so that the superclass name and variables must be accessed by sending messages to LinkedList.

LinkedList superclass

subclass: #AuditTrail
instanceVariableNames: LinkedList instanceVariableString
classVariableNames: LinkedList classVariableString
poolDictionaries: LinkedList sharedPoolString
category: 'Record Keeping'.

AuditTrail is created as a subclass of whichever class is the superclass for LinkedList (LinkedList superclass). Now we copy the categories we are interested in from class LinkedList.

AuditTrail copyCategory: #accessing from: LinkedList.
AuditTrail copyCategory: #testing from: LinkedList.
AuditTrail copyCategory: #adding from: LinkedList.
AuditTrail copyCategory: #enumerating from: LinkedList.
AuditTrail copyCategory: #private from: LinkedList.

AuditTrail declared two instance variable names, firstLink and lastLink, and copied messages first, last, size, isEmpty, add:, addFirst:, and addLast:. We also copied all the messages in the category private on the assumption that at least one of them is needed in the implementation of the external messages.

Some messages in ClassDescription that support storing the class description on an external stream are

ClassDescription instance protocol

filing

fileOutOn: aFileStream

Store a description of the receiver on the file accessed by the argument, aFileStream.

fileOutCategory: categoryName

Create a file whose name is the name of the receiver concatenated by an extension, '.st'. Store on it a description of the messages categorized as categoryName.
`fileOutChangedMessages: setOfChanges on: aFileStream`

The argument, setOfChanges, is a collection of class message pairs that were changed. Store a description of each of these pairs on the file accessed by the argument, aFileStream.

We can write a description of class AuditTrail on the file 'AuditTrail.st' by evaluating the expression

`AuditTrail fileOutOn: (Disk file: 'AuditTrail.st')`

## Class Metaclass

The primary role of a metaclass in the Smalltalk-80 system is to provide protocol for initializing class variables and for creating initialized instances of the metaclass's sole instance. Thus the key messages added by Metaclass are themselves initialization messages—one is sent to Metaclass itself in order to create a subclass of it, and one is sent to an instance of Metaclass in order to create its sole instance.

### Metaclass class protocol

**instance creation**

`subclassOf: superMeta`

Answer an instance of Metaclass that is a subclass of the metaclass, superMeta.

`name: newName`

environment: aSystemDictionary

subclassOf: superClass

instanceVariableNames: stringOfInstVarNames

variable: variableBoolean

words: wordBoolean

pointers: pointerBoolean

classVariableNames: stringOfClassVarNames

poolDictionaries: stringOfPoolNames

category: categoryName

comment: commentString

changed: changed

Each of these arguments, of course, is needed in order to create a fully initialized class.

The Smalltalk-80 programming environment provides a simplified way, using graphical interface techniques, in which the user specifies the information to create new classes.
## Class Class

Instances of Class describe the representation and behavior of objects. Class adds more comprehensive programming support facilities to the basic ones provided in Behavior and more descriptive facilities to the ones provided in ClassDescription. In particular, Class adds the representation for class variable names and shared (pool) variables.

### Class instance protocol

#### accessing instances and variables

<table><tr><td>addClassVarName: aString</td><td>Add the argument, aString, as a class variable of the receiver. The first character of aString must be capitalized; aString can not already be a class variable name.</td></tr><tr><td>removeClassVarName: aString</td><td>Remove the receiver's class variable whose name is the argument, aString. Report an error if it is not a class variable or if it is still being used in a method of the class.</td></tr><tr><td>addSharedPool: aDictionary</td><td>Add the argument, aDictionary, as a pool of shared variables. Report an error if the dictionary is already a shared pool in the receiver.</td></tr><tr><td>removeSharedPool: aDictionary</td><td>Remove the argument, aDictionary, as one of the receiver's pool dictionaries. Report an error if the dictionary is not one of the receiver's pools.</td></tr><tr><td>classPool</td><td>Answer the dictionary of class variables of the receiver.</td></tr><tr><td>initialize</td><td>Initialize class variables.</td></tr></table>

Additional accessing messages store a description of the class on a file, where the file has the same name as that of the class (fileOut), and remove the class from the system (removeFromSystem).

A variety of messages for creating one of the four kinds of subclasses in the system are specified in the method dictionary of Class. In addition, Class provides a message for renaming a class (rename: aString); this message is provided in Class rather than in ClassDescription because it is not an appropriate message to send to a metaclass.

### Class instance protocol

#### instance creation

<table><tr><td>subclass: class_name String</td><td>Create a new class that is a fixed-length (regular) subclass of the receiver. Each of the arguments provides the information needed to initialize the new class and categorize it.</td></tr><tr><td>instanceVariableNames: stringInstVarNames</td><td></td></tr><tr><td>classVariableNames: stringOfClassVarNames</td><td></td></tr><tr><td>poolDictionaries: stringOfPoolNames</td><td></td></tr><tr><td>category: categoryNameString</td><td></td></tr></table>
Three other messages, like the one above except that the first keyword is `variableSubclass:`, `variableByteSubclass:`, or `variableWordSubclass`, support the creation of the other kinds of classes. Note also that the system requires that a subclass of a variable-length class be a variable-length class. When possible, the system makes the appropriate conversion; otherwise, an error is reported to the programmer.

Suppose that every time we created a new subclass, we wanted to install messages for storing and retrieving the instance variables of that class. For example, if we create a class `Record` with instance variable names `name` and `address`, we wish to provide messages `name` and `address`, to respond with the values of these variables, and `name:` and `address:` arguments, to set the values of these variables to the value of the message argument. One way to accomplish this is to add the following method to the instance creation protocol of class `Class`.

```python
accessingSubclass: classname
instanceVariableNames: instVarString
classVariableNames: classVarString
poolDictionaries: stringOfPoolNames
category: categoryName

| newClass |
newClass --> self subclass: classname
    instanceVariableNames: instVarString
classVariableNames: classVarString
poolDictionaries: stringOfPoolNames
category: categoryName.
newClass instVarNames do:
    [ :aName |
        newClass compile: (aName, '
        t', aName) classified: #accessing.
        newClass compile: (aName, ' : argument
        ', aName, ' --> argument.
        argument') classified: #accessing].
    tnewClass
```

The method creates the class as usual, then, for each instance variable name, compiles two methods. The first is of the form

```
name
tname
```

and the second is of the form

```
name: argument
name --> argument.
targument
```
So, if we create the class Record, we can do so by sending Object the
following message.

Object accessingSubclass: #Record
instanceVariableNames: 'name address'
classVariableNames: ''
poolDictionaries: ''
category: 'Example'.

The message is found in the method dictionary of Class, and creates the
following four messages in the category accessing of class Record.

accessing

name

↑name

name: argument

name ← argument.

↑argument

address

↑address

address: argument

address ← argument.

↑argument
<figure><img src="image_132.png" /></figure>

# 17

## The Programming Interface

### Views

* Text Selections

* Menu Selections

### Browsers

* List Selections

* Scrolling

* Class Definitions

### Testing

* Inspectors

### Error Reporting

* Notifiers

* Debuggers
This chapter shows how a programmer adds new classes to the system and then tests and debugs their behavior using the Smalltalk-80 programming environment. The chapter presents a scenario of how a programmer might add class *FinancialHistory* to the system. *FinancialHistory* was used in the first part of this book as an example class. Its protocol and implementation descriptions can be found inside the front cover of this book. This example scenario is not intended as an exhaustive survey of the Smalltalk-80 programming interface. It is intended as an overview that provides motivation for the kinds of graphics support described in subsequent chapters.

A user and the Smalltalk-80 programming environment interact through a *bitmap display screen*, a *keyboard*, and a *pointing device*. The display is used to present graphical and textual views of information to the user. The keyboard is used to present textual information to the system. The pointing device is used to select information on the display screen. Smalltalk-80 uses an indirect pointing device called a *mouse*. A *cursor* on the screen shows the location currently being pointed to by the mouse. The cursor is moved by moving the mouse over a flat surface. The mouse has three buttons, which are used to make different kinds of selection.

## Views

The display screen contains one or more rectangular areas called *views*. The views are displayed on a gray background and may overlap. Each view has a title shown at its upper left corner. Figure 17.1 shows the Smalltalk screen with two overlapping views on it. Their titles are Workspace and System Browser. These two views contain only text; other views might contain pictures or both text and pictures.

The view toward the top of the figure is a *workspace*. It contains text that can be edited or evaluated. The view towards the bottom of the figure is a *system browser*. It allows the class descriptions in the system to be viewed and edited. The arrow in the lower right part of the browser is the *cursor*. It shows the current location of the mouse. At the lower right corner of each figure in this chapter will be a small rectangle containing three ovals arranged side by side. These ovals represent the three mouse buttons. When one of the buttons is pressed, the corresponding oval will be filled in. The buttons will be referred to as the *left*, *middle*, and *right* buttons, even though they may not be arranged side by side on some mice.

A variety of information is typically visible on the Smalltalk-80 display screen. In order to take some action, the user indicates what part of the visible information should be affected. The general activity of directing attention to a particular piece of information is called *selec-*.
<figure><img src="image_133.png" /><figcaption>Figure 17.1</figcaption></figure>

tion. The system gives visual feedback to indicate the current selection. The most common feedback mechanism is to complement a rectangular area of the screen, changing black to white and white to black. To begin using the system, one of the views is selected. The selected view is indicated by complementing only its title. The selected view will be completely displayed, obscuring the overlapping parts of any other views. In Figure 17.1, the browser is the selected view.

A different view can be selected by moving the cursor into part of its rectangular frame that hasn't been overlapped by other views, and then pressing the left button on the mouse. In Figure 17.2, the workspace has been selected. Note that the left mouse button is pressed. The workspace now obscures the overlapped part of the browser.

The Smalltalk-80 text editor provides the ability to select text and to perform editing operations on that selected text. For example, to replace the sequence of characters the standard with my special in the workspace, the old characters are selected and then the new characters are typed.
<figure><img src="image_134.png" /><figcaption>Figure 17.2</figcaption></figure>

Characters are selected using the left mouse button. The cursor is positioned at one end of the selection and the mouse button is pressed (Figure 17.3).

The text selection is now empty—it contains no characters. The position of an empty selection is shown with a dot (an inverted "v"). The

<figure><img src="image_135.png" /><figcaption>Figure 17.3</figcaption></figure>
carat is partially obscured by the cursor in Figure 17.3. While the mouse button remains pressed, the cursor is moved to the other end of the characters to be selected. The selected characters are shown in a complemented rectangle (Figure 17.4).

When the button is released, the selection is complete (Figure 17.5). When characters are typed on the keyboard, they replace the selected characters. After typing the new characters, the selection is empty and positioned at the end of the new characters (Figure 17.6).

<figure><img src="image_136.png" /><figcaption>Figure 17.4</figcaption></figure>

<figure><img src="image_137.png" /><figcaption>Figure 17.5</figcaption></figure>

<figure><img src="image_138.png" /><figcaption>Figure 17.6</figcaption></figure>
## Menu Selections

Another kind of selection used in the user interface is called *menu selection*. The middle and right mouse buttons are used to select commands from one of two menus. When one of these buttons is pressed, a menu appears at the location of the cursor. The menu obtained by pressing the middle button contains commands relevant to the contents of the selected view. When the view contains editable text, as does the workspace, these commands relate to text manipulation. The menu obtained by pressing the right button contains commands relevant to the selected view itself. The middle-button menu may be different in different views, but the right-button menu is always the same.

Characters can be deleted from a piece of text by selecting the characters and then invoking the *cut* command from the middle-button menu. In the next picture, the characters special have been selected and the middle button has been pressed. The menu of commands relevant to the contents of the view has appeared. While the button is held down, the cursor is moved to select the *cut* command in the menu (Figure 17.7). When the button is released, the selected command is carried out. In this example, the selected text is removed (Figure 17.8).

<figure><img src="image_139.png" /><figcaption>Figure 17.7</figcaption></figure>

<figure><img src="image_140.png" /><figcaption>Figure 17.8</figcaption></figure>
A text selection can be treated as a Smalltalk-80 expression and evaluated. There are two commands in the middle-button menu to carry out such an operation, `dolt` and `printIt`. Selecting `dolt` simply evaluates the selected expression and discards the resulting value. Selecting `printIt` evaluates the selected expression and prints its value after the expression. For example, after typing and selecting the expression `Time now`, `printIt` will print out the resulting new instance of `Time` (Figure 17.9). The printed result becomes the current text selection (Figure 17.10).

<figure><img src="image_141.png" /><figcaption>Figure 17.9</figcaption></figure>

<figure><img src="image_142.png" /><figcaption>Figure 17.10</figcaption></figure>

If the cursor is moved outside the menu before the button is released, no command is carried out.

## Browsers

A browser is a view of the classes in the Smalltalk-80 system. Existing classes are examined and changed using a browser. New classes are added to the system using a browser. A browser consists of five rectangular subviews. Along the top are four subviews showing lists. Each list
may or may not have one of its items selected. The selected item in each list is complemented. The contents of the list cannot be edited through the view, they can only be selected. Below the four list subviews is a subview showing some text. That subview is similar to the workspace, allowing the text to be edited. The selections in the four lists determine what text is visible in the lower subview. When a selection has been made in all four lists, the lower subview shows a Smalltalk-80 method. The method is found in a class determined by the selections in the two lists on the left. The method within that class is determined by the selections in the two lists on the right. The browser in Figure 17.11 is showing the method used by Rectangles to respond to the message center.

<figure><img src="image_143.png" /><figcaption>Figure 17.11</figcaption></figure>

The classes in the system are organized into categories. The leftmost list in the browser shows the categories of classes in the system. When a category is selected, the classes in that category are shown in the next list to the right. In the example, the category Graphics-Primitives is selected. That category has four classes in it. When one of these classes is selected, its message categories are shown in the next list to its right.
Since Rectangle is selected, the categories in its instance protocol are displayed. At the bottom of the second list, two rectangular areas are labeled instance and class. One of these will be selected at all times. If class is selected, then the next list to the right shows the categories of class messages; if instance is selected, the list shows the categories of instance messages. When a message category is selected, the selectors of messages in that category are shown in the rightmost list. When one of these message selectors is selected, the corresponding method is displayed in the subview at the bottom of the browser. The method displayed can be edited and the old version can be replaced by the edited version, if desired.

A selection is made in a list by placing the cursor over an item and then pressing and releasing the left mouse button. In Figure 17.12, another item is selected in the browser's rightmost list. Therefore, another method is presented in the lower text subview.

List Selections

<figure><img src="image_144.png" /><figcaption>Figure 17.12</figcaption></figure>
If the left button is pressed and released while the cursor is over the item already selected, that item is deselected (Figure 17.13).

<figure><img src="image_145.png" /><figcaption>Figure 17.13</figcaption></figure>

When a message category is selected, but none of its message selectors have been selected in the rightmost list, the lower subview contains some text describing the various syntactic parts of a method. This text can be replaced with a new method to be added to the system. The new method will be added to the selected category.

If a class category has been selected, but none of its classes has been selected, the lower subview contains some text describing the various parts of a class definition. This text is in the form of a message to a class (Object, in this case) asking it to create a new subclass of itself (Figure 17.14).
<figure><img src="image_146.png" /><figcaption>Figure 17.14</figcaption></figure>
Scrolling

A view may not be large enough to show all of the information it
might. For example, many of the lists viewed by the browser are too
long to be completely displayed in the space available. The view can be
positioned on different parts of the list by using a *scroll bar*. A scroll
bar is a rectangular area that appears to the left of the subview con-
taining the cursor. The gray box in the scroll bar indicates which part
of the total list is visible in the view. The height of the scroll bar repre-
sents the length of the entire list. The part of the scroll bar occupied by
the gray box indicates the part of the list that is visible.

<figure><img src="image_147.png" /><figcaption>Figure 17.15</figcaption></figure>

By moving the mouse into the scroll bar, another part of the list can be
shown. This is called *rolling*. When the cursor is in the right half of
the scroll bar, it takes the shape of an upward pointing arrow. If the
left mouse button is pressed, the items in the list appears to move up in
the subview and new items become visible at the bottom. When the
cursor is in the left half of the scroll bar, its shape is a downward point-
ing arrow; pressing the left button makes an earlier part of the list visi-
ble. For example, the browser's leftmost list can be scrolled to show
categories earlier in the list (Figure 17.15).

Views containing text can also be scrolled if the view is too small to
show all the text.
A new class can be added to the system by selecting a class category and editing the text describing the parts of a class definition. The FinancialHistory example will be added to the category named New Projects.

While text is being changed in the lower subview, it may not accurately represent a class definition or a method. The accept command in the middle-button menu is used to indicate that the editing has been completed and the class definition or method should be added to the system (Figures 17.16 and 17.17).

## Class Definitions

<figure><img src="image_148.png" /><figcaption>Figure 17.16</figcaption></figure>

<figure><img src="image_149.png" /><figcaption>Figure 17.17</figcaption></figure>
The menu that appears when the middle button is pressed is differ-
ent in each of the browser's subviews. In the subview showing the class-
es in a category, the menu includes an item called definition. This com-
mand causes the class definition of an existing class to be displayed
(Figures 17.18 and 17.19).

This class definition can then be modified with the standard text
editing operations. After changing the text, accept must be selected
again in the middle-button menu. For example, an instance variable
could be added to all Rectangles by adding its name to the appropriate
place in the class definition.

<figure><img src="image_150.png" /><figcaption>Figure 17.18</figcaption></figure>

<figure><img src="image_151.png" /><figcaption>Figure 17.19</figcaption></figure>
Another item in the middle-button menu for the class list is categories. When it is selected, the message categorization is shown in the bottom subview (Figures 17.20 and 17.21).

<figure><img src="image_152.png" /><figcaption>Figure 17.20</figcaption></figure>

<figure><img src="image_153.png" /><figcaption>Figure 17.21</figcaption></figure>

The new class has a single, empty message category called As yet unclassified.
The categorization can be changed by editing the text and selecting
accept (Figures 17.22 and 17.23). Notice the change in the third subview
from the left of Figure 17.23. There are now three categories, transac-
tion recording, inquiries, and private.

<figure><img src="image_154.png" /><figcaption>Figure 17.22</figcaption></figure>

<figure><img src="image_155.png" /><figcaption>Figure 17.23</figcaption></figure>
After a new class has been added to the system, methods can be add-
ed by selecting categories and editing method templates (Figures 17.24
and 17.25).

Notice the change in the rightmost subview of Figure 17.25. The se-
lector of the new method is added to the (previously empty) list and be-
comes the current selection.

<figure><img src="image_156.png" /><figcaption>Figure 17.24</figcaption></figure>

<figure><img src="image_157.png" /><figcaption>Figure 17.25</figcaption></figure>
## Testing

After the methods shown in Chapter 5 have been added to `FinancialHistory`, instances can be created and tested by sending them messages. First, a new global variable will be added to the system by sending the message `at:put`: to the dictionary of global variables whose name is `Smalltalk`. The first argument of `at:put`: is the name of the global variable and the second is the initial value. This global variable will be used to refer to the instance being tested (Figure 17.26).

<figure><img src="image_158.png" /><figcaption>Figure 17.26</figcaption></figure>
Messages are sent to HouseholdFinances by typing expressions in the workspace and evaluating them by invoking the commands `dolt` or `printIt` (Figure 17.27). Several expressions can be selected and evaluated at one time. The expressions are separated by periods (Figure 17.28).

<figure><img src="image_159.png" /><figcaption>Figure 17.27</figcaption></figure>

<figure><img src="image_160.png" /><figcaption>Figure 17.28</figcaption></figure>
Selecting `printIt` instead of `dolt` displays the result following the expression (Figures 17.29 and 17.30).

<figure><img src="image_161.png" /><figcaption>Figure 17.29</figcaption></figure>

<figure><img src="image_162.png" /><figcaption>Figure 17.30</figcaption></figure>
## Inspectors

An inspector is a view of an object's instance variables. An inspector is created by sending `inspect` to the object whose instance variables are to be viewed (Figure 17.31).

After `inspect` has been sent, the user is prompted for a rectangular area in which to display the inspector. The shape of the cursor is changed to indicate that the upper left corner of the rectangular area should be specified (Figure 17.32).

<figure><img src="image_163.png" /><figcaption>Figure 17.31</figcaption></figure>

<figure><img src="image_164.png" /><figcaption>Figure 17.32</figcaption></figure>
The cursor is moved to the desired location and the left mouse button is pressed and held down. The shape of the cursor is changed again to indicate that the lower right corner of the rectangular area should now be specified. As long as the left mouse button remains pressed, the prospective new rectangular frame is displayed (Figure 17.33).

When the button is released, the inspector is displayed in the selected area (Figure 17.34).

The title of the inspector is the name of the inspected object's class.

<figure><img src="image_165.png" /><figcaption>Figure 17.33</figcaption></figure>

<figure><img src="image_166.png" /><figcaption>Figure 17.34</figcaption></figure>
An inspector has two subviews. The left subview shows a list containing self and the names of the object's instance variables. When one of the elements of the list is selected, the corresponding value is printed in the subview to the right (Figures 17.35 and 17.36). The text that appears in the righthand subview is obtained as a result of sending printString to the selected object. Selecting the element self at the top of the list, prints the object being inspected (Figure 17.37).

<figure><img src="image_167.png" /><figcaption>Figure 17.35</figcaption></figure>

<figure><img src="image_168.png" /><figcaption>Figure 17.36</figcaption></figure>
<figure><img src="image_169.png" /><figcaption>Figure 17.37</figcaption></figure>

## Error Reporting

When an error is encountered, the process in which the error occurred is suspended and a view of that process is created. Suspended processes can be viewed in two ways, with *notifiers* and with *debuggers*. A notifier provides a simple description of the process at the time of the error. A debugger provides a more detailed view and also the ability to change the state of the suspended process before resuming it.

As an example of error reporting, we will follow the addition and debugging of several new methods in `FinancialHistory`. The following methods contain several errors which will be "discovered" in the testing process. The intention of these new methods is to allow a `FinancialHistory` to give a summary report of its state.

### report

| reportStream |
reportStream --> WriteStream on: (String new: 10).
reportStream cr.
reportStream nextPutAll: 'Expenses' .
reportStream cr.
self expenseReasons do:
  [ :reason | reportStream tab.
    reportStream nextPutAll: reason.
    reportStream tab.
    reportStream nextPutAll: (self totalSpentFor: reason).
    reportStream cr].
reportStream nextPutAll: 'Incomes'.

reportStream cr.

self incomeSources do:

[ :source | reportStream tab.

reportStream nextPutAll: source.

reportStream tab.

reportStream nextPutAll: (self totalReceivedFrom: source).

reportStream cr].

treportStream contents

**incomeSources**

tincomes keys

**expenditureReasons**

texpenditures keys

A new category is added and the new methods typed in and accepted (Figure 17.38).

After adding the new methods, the instance of FinancialHistory can be asked for a report by evaluating an expression in the workspace (Figure 17.39). Instead of printing the report, a notifier appears on the screen (Figure 17.40).

<figure><img src="image_170.png" /><figcaption>Figure 17.38</figcaption></figure>
<figure><img src="image_171.png" /><figcaption>Figure 17.39</figcaption></figure>

<figure><img src="image_172.png" /><figcaption>Figure 17.40</figcaption></figure>
Notifiers

A notifier is a simple view of a process suspended after an error. The notifier's title indicates the nature of the error. Notifiers are created by sending an object the message error. The argument of the message becomes the title of the notifier. The notifier shown in Figure 17.40 indicates that the message expenseReasons was sent to an object that did not understand it. The list visible in the notifier shows part of the state of the suspended process.

The cause of this error is evident from the title of the notifier. The message added to FinancialHistory was expenditureReasons not expenseReasons. The notifier and the erroneous process can be discarded by selecting the command close in the right mouse-button menu (Figure 17.41).

<figure><img src="image_173.png" /><figcaption>Figure 17.41</figcaption></figure>
The misspelling in report can be corrected in the browser (Figures 17.42 and 17.43).

<figure><img src="image_174.png" /><figcaption>Figure 17.42</figcaption></figure>

<figure><img src="image_175.png" /><figcaption>Figure 17.43</figcaption></figure>

After fixing the misspelling in the browser, the original expression can be evaluated in the workspace again (Figures 17.44 and 17.45).

This creates another notifier. The cause of this error is not as obvious. The message do: was sent to an object that did not understand it. In order to learn more about the error, a more detailed view of the suspended process can be obtained by selecting the command debug in the middle-button menu.
<figure><img src="image_176.png" /><figcaption>Figure 17.44</figcaption></figure>

<figure><img src="image_177.png" /><figcaption>Figure 17.45</figcaption></figure>
Debuggers

A debugger is a view of a suspended process that reveals more details than a notifier reveals. When debug is selected in a notifier's middle-button menu, a debugger is created viewing the same process the notifier viewed (Figure 17.46). After selecting debug, the user is prompted to supply a rectangular area in which to display the debugger. The rectangle is specified in the same way that the rectangular frame for a new inspector is specified (Figure 17.47).

<figure><img src="image_178.png" /><figcaption>Figure 17.46</figcaption></figure>

The debugger has six subviews. The top subview shows the same list that was visible through the notifier. This list gives a partial history of the process in which the error occurred. Each item corresponds to a message that was sent and whose response is not yet completed. The item contains the name of the receiver's class and the selector of the message, separated by ">>". The last item visible in the list, `FinancialHistory >>` report, indicates that an instance of `FinancialHistory` received the message report. This message was sent when the middle-button menu command `printIt` was selected while the expression `HouseholdFinances report` was the text selection. When one of the items in the debugger's upper list is selected, the method invoked by the corresponding message is displayed in the subview immediately below.
<figure><img src="image_179.png" /><figcaption>Figure 17.47</figcaption></figure>
When a method is displayed, the last message sent before the process
was suspended is complemented. Figure 17.48 shows that the message
do: was sent to the result of the expression self.expenditureReasons.
The next item up on the list, Set>>do:, indicates that the receiver of
do: was an instance of Set. The method invoked can be seen by
selecting Set>>do: in the list.

<figure><img src="image_180.png" /><figcaption>Figure 17.48</figcaption></figure>

Figure 17.49 shows that this method sent a message to the object 1. The next item up on the list, SmallInteger(Number) >> to:do: shows that the receiver was an instance of SmallInteger. When the method invoked by a message was found in a superclass of the receiver's class, the name of that superclass is included in parentheses after the receiver's direct class. In the example, the method for to:do: was found in class Number.
<figure><img src="image_181.png" /><figcaption>Figure 17.49</figcaption></figure>

The top item on the list, `SmallInteger(Object) >> doesNotUnderstand:`, shows the last thing that happened before the process was suspended—an instance of `SmallInteger` received the message `doesNotUnderstand:`. This message was sent by the system when the `do:` message was not found in `SmallInteger` or in any of its superclasses. The `doesNotUnderstand:` message invoked a method that suspended the process and created the notifier viewing it. The second item from the top of the list, `WriteStream.Stream) >> nextPutAll:`, indicates that the misunderstood `do:` message was sent from the method for `nextPutAll:` in class `Stream`. Figure 17.50 shows the debugger with that item selected. The method displayed shows that `do:` was sent to the object named `aCollection`, which was provided as the argument of `nextPutAll`.

The lower four subviews of a debugger are used to find the value of the variables used in the method. They function like two inspectors. The leftmost subview shows a list of the receiver (`self`) and its instance variable names. The third subview from the left shows the argument
<figure><img src="image_182.png" /><figcaption>Figure 17.50</figcaption></figure>

names and temporary variable names. When a name is selected in either one of these lists, the value of the associated variable is shown in the subview to its right. To display the receiver of the `do:` message, `aCollection` is selected in Figure 17.50.

The source of this error appears to be that the `Stream` was expecting a collection of elements as the argument of `nextPutAll`: and it got a number, 700, instead. Selecting the next item down from the top list shows where the argument came from. The argument was the result of evaluating the expression (`self totalSpentFor: reason`). In Figure 17.51, selections have been made in the bottom subviews to display the values of the instance variable, `expenditures`, and the argument, `reason`.

When text is selected and evaluated in the method displayed in the browser, the variable names are interpreted in that context. So the argument to `nextPutAll`: can be found by re-executing the expression (`self totalSpentFor: reason`) and printing the result (Figure 17.52).
<figure><img src="image_183.png" /><figcaption>Figure 17.51</figcaption></figure>

<figure><img src="image_184.png" /><figcaption>Figure 17.52</figcaption></figure>
<figure><img src="image_185.png" /><figcaption>Figure 17.53</figcaption></figure>

<figure><img src="image_186.png" /><figcaption>Figure 17.54</figcaption></figure>
The result is 700, as expected (Figure 17.53).

The report method had intended that the character representation of 700 be appended to reportStream, but it appended the number itself instead. This bug is fixed by sending the number the message printString. The correction can be made in the debugger (Figure 17.54). Now the expression can be evaluated again. The report is now successfully printed in the workspace (Figure 17.55).

<figure><img src="image_187.png" /><figcaption>Figure 17.55</figcaption></figure>

This completes the overview of the Smalltalk-80 programming interface. The ability to support this type of interaction with the user motivates the nature of many of the graphics classes discussed in subsequent chapters.
# 18

## The Graphics Kernel

**Graphical Representation**

**Graphical Storage**

**Graphical Manipulation**

* Source and Destination Forms

* Clipping Rectangle

* Halftone Form

* Combination Rule

**Classes Form and Bitmap**

**Spatial Reference**

* Class Point

* Class Rectangle

* Class BitBlt

**Line Drawing**

**Text Display**

**Simulation of BitBlt**

* Efficiency Considerations

<figure><img src="image_188.png" /></figure>
Object

Magnitude

Character

Date

Time

Number

Float

Fraction

Integer

LargeNegativeInteger

LargePositiveInteger

SmallInteger

LookupKey

Association

Link

Process

Collection

SequenceableCollection

LinkedList

Semaphore

ArrayedCollection

Array

Bitmap

DisplayBitmap

RunArray

String

Symbol

Text

ByteArray

Interval

OrderedCollection

SortedCollection

Bag

MappedCollection

Set

Dictionary

IdentityDictionary

Stream

PositionableStream

ReadStream

WriteStream

ReadWriteStream

ExternalStream

FileStream

Random

File

FileDirectory

FilePage

UndefinedObject

Boolean

False

True

ProcessorScheduler

Delay

SharedQueue

Behavior

ClassDescription

Class

MetaClass

Point

Rectangle

BitBit

CharacterScanner

Pen

DisplayObject

DisplayMedium

Form

Cursor

DisplayScreen

InfiniteForm

OpaqueForm

Path

Arc

Circle

Curve

Line

LinearFit

Spline
## Graphical Representation

Figure 18.1 shows a view of the display screen for a Smalltalk-80 system. It illustrates the wide range of graphical idiom available to the system. Rectangular areas of arbitrary size are filled with white, black, and halftone patterns. Text, in various typefaces, is placed on the screen from stored images of the individual characters. Halftone shades are "brushed" by the user to create freehand paintings. Moreover, although not shown on the printed page, images on the display can be moved or sequenced in time to provide animation.

The example interaction with the system given in the previous chapter illustrated some of the ways in which objects can be observed and manipulated graphically. Meaningful presentation of objects in the system demands maximum control over the display medium. One approach that provides the necessary flexibility is to allow the brightness of every discernible point in the displayed image to be independently controlled. An implementation of this approach is a contiguous block of storage in which the setting of each *bit* is mapped into the illumination of a corresponding picture element, or *pixel*, when displaying the image. The block of storage is referred to as a * bitmap*. This type of display is called a * bitmapped display*. The simplest form of bitmap allows only two brightness levels, white and black, corresponding to the stored bit values 0 or 1 respectively. The Smalltalk-80 graphics system is built around this model of a display medium.

## Graphical Storage

Images are represented by instances of class Form. A Form has height and width, and a bitmap, which indicates the white and black regions of the particular image being represented. Consider, for example, the man-shape in Figure 18.2. The height of the Form is 40, its width is 14, and its appearance is described by the pattern of ones and zeros (shown as light and dark squares) in its bitmap. The height and width of the Form serve to impose the appropriate two-dimensional ordering on the otherwise unstructured data in the bitmap. We shall return to the representation of Forms in more detail later in this chapter.

New Forms are created by combining several Forms. The freehand drawing in the center of Figure 18.1 is an example of a large Form that was created by combining and repeating several Forms that serve as "paint brushes" in a Smalltalk-80 application system. The text in Figure 18.1 is a structured combination of Forms representing characters.

A Form can be presented to the display hardware as a buffer in memory of the actual data or of the image to be shown on a display
<figure><img src="image_189.png" /><figcaption>Figure 18.1</figcaption></figure>

WORD GRAPHICS
<figure><img src="image_190.png" /><figcaption>Figure 18.2</figcaption></figure>

screen. Since the interface to the hardware is through a Form, there is no difference between combining images internally and displaying them on the screen. Animation can be displayed smoothly by using one Form as the display Form while the next image to be displayed is prepared in a second Form. As each image is completed, the two Forms exchange roles, causing the new image to be displayed and making the Form with the old image available for building yet another image in the sequence.

The Forms used as buffers for data to be shown on the display screen are instances of class DisplayScreen, a subclass of Form. Contiguous storage of bits is provided by instances of class Bitmap. DisplayScreen's bitmap is an instance of DisplayBitmap, a subclass of Bitmap. DisplayScreen and DisplayBitmap provide protocol specific to the actual hardware and to the fact that the Form represents the whole display screen rather than potential parts of it.

## Graphical Manipulation

A basic operation on Forms, referred to as *BitBlt*, supports a wide range of graphical presentation. All text and graphic objects in the system are created and modified using this single graphical operation. The name
"BitBlt" derives from the generalization of data transfer to arbitrary bit locations, or pixels. One of the first computers on which a Smalltalk system was implemented had an instruction called BLT for *block transfer* of 16-bit words, and so "bit block transfer" became known as BitBlt.

Operations are represented by messages to objects. So BitBlt could have been implemented with a message to class Form. However, because BitBlt's are fairly complicated operations to specify, they are represented by objects. These objects are instances of the class named BitBlt. The basic operation is performed by sending an appropriately initialized instance of BitBlt the message copyBits. The BitBlt operation is intentionally a very general operation, although most applications of it are graphically simple, such as "move this rectangle of pixels from here to there."

Figure 18.3 illustrates the process of copying a character of text into a region on the display. This operation will serve to illustrate most of the characteristics of BitBlt that are introduced in the remainder of this section.

*Source and Destination Forms*

The BitBlt copy operation involves two Forms, a source and a destination. The source in the example in Figure 18.3 is a *font* containing a set of character glyphs depicted in some uniform style and scale, and packed together horizontally. The destination in the example is assumed to be a Form that is used as the display buffer. Pixels are copied out of the source and stored into the destination. The width and height of the transfer correspond to the character size. The source x and y coordinates give the character's location in the font, and the destination coordinates specify the position on the display where its copy will appear.

*Clipping Rectangle*

BitBlt includes in its specification a rectangular area which limits the region of the destination that can be affected by its operation, independent of the other destination parameters. We call this area the *clipping rectangle*. Often it is desirable to display a partial *window* onto larger scenes, and the clipping rectangle ensures that all picture elements fall inside the bounds of the window. By its inclusion in the BitBlt primitive, the clipping function can be done efficiently and in one place, rather than being replicated in all application programs.

Figure 18.4 illustrates the result of imposing a clipping rectangle on the example of Figure 18.3. Pixels that would have been placed outside the clipping rectangle (the left edge of the "N" and half of the word "the") have not been transferred. Had there been other characters that fell above or below this rectangle, they would have been similarly clipped.
destForm
destX = 67
destY = 10

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

width = 7
height = 13

sourceForm

sourceX = 248
sourceY = 0

<caption>Figure 18.3</caption>

destForm
clipX = 6
clipY = 4
clipWidth = 58
clipHeight = 23

<figure><img src="image_192.png" /><figcaption>Figure 18.4</figcaption></figure>
### Halftone Form

Often it is desirable to fill areas with a regular pattern that provides the effect of gray tone or texture. To this end, BitBlt provides for reference to a third Form containing the desired pattern. This Form is referred to as a halftone or *mask*. It is restricted to have height and width of 16. When halftoning is specified, this pattern is effectively repeated every 16 units horizontally and vertically over the entire destination.

There are four "modes" of supplying pixels from the source and halftone controlled by supplying `nil` for the source form or the halftone form:

0. no source, no halftone (supplies solid black)

1. halftone only (supplies halftone pattern)

2. source only (supplies source pixels)

3. source AND halftone (supplies source bits masked by halftone pattern)

Figure 18.5 illustrates the effect of these four modes with the same source and destination and a regular gray halftone.

<figure><img src="image_193.png" /><figcaption>Figure 18.5</figcaption></figure>

### Combination Rule

The examples above have all determined the new contents of the destination based only on the source and halftone, storing directly into the destination. The previous contents of the destination can also be taken into account in determining the result of the copying.

There are 16 possible rules for combining each source element `S` with the corresponding destination element `D` to produce the new destination element `D'`. Each rule must specify a white or black result for each of the four cases of source being white or black, and destination being white or black.
Figure 18.6 shows a box with four cells corresponding to the four cases encountered when combining source S and destination D. For instance, the cell numbered 2 corresponds to the case where the source was black and the destination was white. By appropriately filling the four cells with white or black, the box can be made to depict any combination rule. The numbers in the four cells map the rule as depicted graphically to the integer value which selects that rule. For example, to specify that the result should be black wherever the source or destination (or both) was black, we would blacken the cells numbered 4, 2, and 1. The associated integer for specifying that rule is the sum of the blackened cell numbers, or $4 + 2 + 1 = 7$.

<figure><img src="image_194.png" /><figcaption>Figure 18.6</figcaption></figure>

Figure 18.7 illustrates four common combination rules graphically. In addition, each is described by a combination diagram, its integer rule number, and the actual logical function being applied. The full set of 16 combination rules appears later in the chapter as part of the detailed simulation of BitBlt.

<figure><img src="image_195.png" /><figcaption>Figure 18.7</figcaption></figure>
## Classes Form and Bitmap

Figure 18.8 shows further information about the Form shown in Figure 18.2. The width and height are stored as Integers. The actual pixels are stored in a separate object which is an instance of class Bitmap. Bitmaps have almost no protocol, since their sole purpose is to provide storage for Forms. They also have no intrinsic width and height, apart from that laid on by their owning Form, although the figure retains this structure for clarity. It can be seen that space has been provided in the Bitmap for a width of 16; this is a manifestation of the hardware organization of storage and processing into 16-bit *words*. Bitmaps are allocated with an integral number of words for each row of pixels. This row size is referred to as the *raster size*. The integral word constraint on raster size facilitates movement from one row to the next within the operation of BitBlt, and during the scanning of the display screen by the hardware. While this division of memory into words is significant at the primitive level, it is encapsulated in such a way that none of the higher-level graphical components in the system need consider the issue of word size.

Two classes, Rectangle and Point, are used extensively in working with stored images. A Point contains x and y coordinate values and is used to refer to a pixel location in a Form; a Rectangle contains two Points—the top left corner and the bottom right corner—and is used to define a rectangular area of a Form.

Class Form includes protocol for managing a rectangular pattern of black and white dots. The bitmap of a Form can be (re)set by copying bits from a rectangular area of the display screen (fromDisplay:), and the extent and offset of the Form can be set (extent:, extent:offset:). Two messages provide access to the individual bits (valueAt: and valueAt:put:). Constants for modes and masks are known to class Form and can be obtained by the following class messages of Form.

### Form instance protocol

*   initialize-release
    fromDisplay: aRectangle
    Copy the bits from the display screen within the boundaries defined by the argument, aRectangle, into the receive's bitmap.

*   accessing
    extent: aPoint
    Set the width and height of the receiver to be the coordinates of the argument, aPoint.

extent: extentPoint offset: offsetPoint
    Set the width and height of the receiver to be the coordinates of the argument, extentPoint, and the offset to be offsetPoint.
<figure><img src="image_196.png" /><figcaption>Figure 18.8</figcaption></figure>

pattern

valueAt: aPoint

Answer the bit, 0 or 1, at location aPoint within the receiver's bitmap.

valueAt: aPoint put: bitCode

Set the bit at location aPoint within the receiver's bitmap to be bitCode, either 0 or 1.

Form class protocol

instance creation

fromDisplay: aRectangle

Answer a new Form whose bits are copied from the display screen within the boundaries defined by the argument, aRectangle, into the receiver's bitmap.

mode constants

erase

Answer the Integer denoting mode erase.

over

Answer the Integer denoting mode over.

reverse

Answer the Integer denoting mode reverse.

under

Answer the Integer denoting mode under.
mask constants

<table><tr><td>black</td><td>Answer the Form denoting a black mask.</td></tr><tr><td>darkGray</td><td>Answer the Form denoting a dark gray mask.</td></tr><tr><td>gray</td><td>Answer the Form denoting a gray mask.</td></tr><tr><td>lightGray</td><td>Answer the Form denoting a light gray mask.</td></tr><tr><td>veryLightGray</td><td>Answer the Form denoting a very light gray mask.</td></tr><tr><td>white</td><td>Answer the Form denoting a white mask.</td></tr></table>

Spatial Reference

Since the images represented by Forms are inherently two-dimensional, image manipulation is simplified by providing objects representing two-dimensional locations and areas. Instances of class Point represent locations and instances of class Rectangle represent areas.

Class Point

A Point represents an x-y pair of numbers usually designating a pixel in a Form. Points refer to pixel locations relative to the top left corner of a Form (or other point of reference). By convention, x increases to the right and y down, consistent with the layout of text on a page and the direction of display scanning. This is in contrast to the "right-handed" coordinate system in which y increases in the upward direction.

A Point is typically created using the binary message @ to a Number. For example, the result of evaluating the expression

200 @ 150

is a Point with x and y coordinates 200 and 150. In addition, the class protocol of Point supports the instance creation message x: xInteger y: yInteger.

Point x: 200 y: 150

represents the same location as 200@150. The instance protocol for Point supports accessing messages and messages for comparing two Points.
Point instance protocol

accessing

x Answer the x coordinate.

x: aNumber Set the x coordinate to be the argument, aNumber.

y Answer the y coordinate.

y: aNumber Set the y coordinate to be the argument, aNumber.

comparing

< aPoint Answer whether the receiver is above and to the left of the argument, aPoint.

<= aPoint Answer whether the receiver is neither below nor to the right of the argument, aPoint.

> aPoint Answer whether the receiver is below and to the right of the argument, aPoint.

> = aPoint Answer whether the receiver is neither above nor to the left of the argument, aPoint.

max: aPoint Answer the lower right corner of the rectangle uniquely defined by the receiver and the argument, aPoint.

min: aPoint Answer the upper left corner of the rectangle uniquely defined by the receiver and the argument, aPoint.

With respect to the coordinates labeled in Figure 18.9, example expressions are

<table><thead><tr><td>expression</td><td>result</td></tr></thead><tbody><tr><td>(45@230) &lt; (175@270)</td><td>true</td></tr><tr><td>(45@230) &lt; (175@200)</td><td>false</td></tr><tr><td>(45@230) &gt; (175@200)</td><td>false</td></tr><tr><td>(175@270) &gt; (45@230)</td><td>true</td></tr><tr><td>(45@230) max: (175@200)</td><td>175@230</td></tr><tr><td>(45@230) min: (175@200)</td><td>45@200</td></tr></tbody></table>

Arithmetic can be carried out between two Points or between a Point and a Number (a scaling factor). Each of the arithmetic messages takes either a Point or a Number (a scalar) as an argument, and returns a new Point as the result. Truncation and round off messages, similar to those for Numbers, are also provided in the instance protocol of Point.

Point instance protocol

arithmetic

* scale

Answer a new Point that is the product of the receiver and the argument, scale.
<figure><img src="image_197.png" /><figcaption>Figure 18.9</figcaption></figure>

<table><tr><td>+</td><td>delta</td><td>Answer a new Point that is the sum of the receiver and the argument, delta.</td></tr><tr><td>-</td><td>delta</td><td>Answer a new Point that is the difference of the receiver and the argument, delta.</td></tr><tr><td>/</td><td>scale</td><td>Answer a new Point that is the quotient of the receiver and the argument, scale.</td></tr><tr><td>//</td><td>scale</td><td>Answer a new Point that is the quotient (defined by division with truncation toward negative infinity) of the receiver and the argument, scale.</td></tr><tr><td>abs</td><td></td><td>Answer a new Point whose x and y are the absolute values of the receiver's x and y.</td></tr><tr><td>truncation and round off</td><td>rounded</td><td>Answer a new Point that is the receiver's x and y rounded.</td></tr><tr><td>truncateTo: grid</td><td></td><td>Answer a new Point that is the receiver's x and y truncated to the argument, grid.</td></tr></table>
Thus

<table><thead><tr><td>expression</td><td>result</td></tr></thead><tbody><tr><td>(45@230) + (175@300)</td><td>220@530</td></tr><tr><td>(45@230) + 175</td><td>220@405</td></tr><tr><td>(45@230) - (175@300)</td><td>-130@-70</td></tr><tr><td>(160@240) / 50</td><td>(16/5)@ (24/5)</td></tr><tr><td>(160@240) // 50</td><td>3@4</td></tr><tr><td>(160@240) // (50@50)</td><td>3@4</td></tr><tr><td>((45@230) - (175@300)) abs</td><td>130@70</td></tr><tr><td>(120.5 @ 220.7) rounded</td><td>121@221</td></tr><tr><td>(160 @ 240) truncateTo: 50</td><td>150@200</td></tr></tbody></table>

Various other operations can be performed on Points including computing the distance between two Points, computing the dot product of two Points, transposing a point, and determining Points within some gridded range.

Point instance protocol

point functions

dist: aPoint Answer the distance between the argument, aPoint, and the receiver.

dotProduct: aPoint Answer a Number that is the dot product of the receiver and the argument, aPoint.

grid: aPoint Answer a Point to the nearest rounded grid modules specified by the argument, aPoint.

normal Answer a Point representing the unit vector rotated 90 deg clockwise.

transpose Answer a Point whose x is the receiver's y and whose y is the receiver's x.

truncatedGrid: aPoint Answer a Point to the nearest truncated grid modules specified by the argument, aPoint.

Examples are

<table><thead><tr><td>expression</td><td>result</td></tr></thead><tbody><tr><td>(45@230) dist: 175@270</td><td>136.015</td></tr><tr><td>(160@240) dotProduct: 50@50</td><td>20000</td></tr><tr><td>(160@240) grid: 50@50</td><td>150@250</td></tr><tr><td>(160@240) normal</td><td>-0.83105 @ 0.5547</td></tr><tr><td>(160@240) truncatedGrid: 50@50</td><td>150@200</td></tr><tr><td>(175@300) transpose</td><td>300@175</td></tr></tbody></table>

Points and Rectangles are used together as support for graphical manipulation. A Rectangle contains two Points—origin, which specifies the
top left corner, and corner, which indicates the bottom right corner of the region described. Class Rectangle provides protocol for access to all the coordinates involved, and other operations such as intersection with other rectangles. Messages to a Point provide an infix way to create a Rectangle with the Point as the origin.

Point instance protocol

converting

corner: aPoint

Answer a Rectangle whose origin is the receiver and whose corner is the argument, aPoint.

extent: aPoint

Answer a Rectangle whose origin is the receiver and whose extent is the argument, aPoint.

Thus (45@200) corner: (175@270) represents the rectangular area shown earlier in the image of display coordinates.

Class Rectangle

Instances of Rectangle represent rectangular areas of pixels. Arithmetic operations take points as arguments and carry out scaling and translating operations to create new Rectangles. Rectangle functions create new Rectangles by determining intersections of Rectangles with Rectangles.

In addition to the messages to Point by which Rectangles can be created, class protocol for Rectangle supports three messages for creating instances. These messages specify either the boundaries of the rectangular area, the origin and corner coordinates, or the origin and width and height of the area.

Rectangle class protocol

instance creation

left: leftNumber right: rightNumber top: topNumber bottom: bottomNumber

Answer a Rectangle whose left, right, top, and bottom coordinates are determined by the arguments.

origin: originPoint corner: cornerPoint

Answer a Rectangle whose top left and bottom right corners are determined by the arguments, originPoint and cornerPoint.

origin: originPoint extent: extentPoint

Answer a Rectangle whose top left corner is originPoint and width by height is extentPoint.

The accessing protocol for Rectangle is quite extensive. It supports detailed ways of referencing eight significant locations on the boundary of the Rectangle. These points are shown in Figure 18.10.

Messages for accessing these positions have selectors with names like those shown in the diagram.
<figure><img src="image_198.png" /><figcaption>Figure 18.10</figcaption></figure>

Rectangle instance protocol

accessing

topLeft

Answer the Point at the top left corner of the receiver.

topCenter

Answer the Point at the center of the receiver's top horizontal line.

topRight

Answer the Point at the top right corner of the receiver.

rightCenter

Answer the Point at the center of the receiver's right vertical line.

bottomRight

Answer the Point at the bottom right corner of the receiver.

bottomCenter

Answer the Point at the center of the receiver's bottom horizontal line.

bottomLeft

Answer the Point at the bottom left corner of the receiver.

leftCenter

Answer the Point at the center of the receiver's left vertical line.

center

Answer the Point at the center of the receiver.

area

Answer the receiver's area, the product of width and height.

width

Answer the receiver's width.

height

Answer the receiver's height.

extent

Answer the Point receiver's width @ receiver's height.

top

Answer the position of the receiver's top horizontal line.

right

Answer the position of the receiver's right vertical line.

bottom

Answer the position of the receiver's bottom horizontal line.

left

Answer the position of the receiver's left vertical line.
<table><tr><td>origin</td><td>Answer the Point at the top left corner of the receiver.</td></tr><tr><td>corner</td><td>Answer the Point at the bottom right corner of the receiver.</td></tr></table>

Suppose the Rectangle referred to as frame is created by the expression

frame - Rectangle origin: 100@100 extent: 150@150

then

<table><thead><tr><td>expression</td><td>result</td></tr></thead><tbody><tr><td>frame topLeft</td><td>100@100</td></tr><tr><td>frame top</td><td>100</td></tr><tr><td>frame rightCenter</td><td>250@175</td></tr><tr><td>frame bottom</td><td>250</td></tr><tr><td>frame center</td><td>175@175</td></tr><tr><td>frame extent</td><td>150@150</td></tr><tr><td>frame area</td><td>22500</td></tr></tbody></table>

Each of the Rectangle's locations can be modified by an accessing message whose keyword is one of the positions named in Figure 18.10. In addition, the width and height can be set with the messages width: and height: , respectively. Two messages are listed below that are commonly used in the implementation of the system programming interface in order to reset the variables of a Rectangle.

### Rectangle instance protocol

accessing

origin: originPoint corner: cornerPoint

Set the points at the top left corner and the bottom right corner of the receiver.

origin: originPoint extent: extentPoint

Set the point at the top left corner of the receiver to be originPoint and set the width and height of the receiver to be extentPoint.

Rectangle functions create new Rectangles and compute relationships between two Rectangles.

### Rectangle instance protocol

rectangle functions

amountToTranslateWithin: aRectangle

Answer a Point, delta, such that the receiver, when moved by delta, will force the receiver to lie within the argument, aRectangle.
<table><caption>Figure 18.11 shows three Rectangles, A, B, and C, created as follows.</caption><tr><td>areasOutside: aRectangle</td><td>Answer a collection of Rectangles comprising the parts of the receiver which do not lie within the argument, aRectangle.</td></tr><tr><td>expandBy: delta</td><td>Answer a Rectangle that is outset from the receiver by delta, where delta is a Rectangle, Point, or scalar.</td></tr><tr><td>insetBy: delta</td><td>Answer a Rectangle that is inset from the receiver by delta, where delta is a Rectangle, Point, or scalar.</td></tr><tr><td>insetOriginBy: originDeltaPoint cornerBy: cornerDeltaPoint</td><td>Answer a Rectangle that is inset from the receiver by originDeltaPoint at the origin and cornerDeltaPoint at the corner.</td></tr><tr><td>intersect: aRectangle</td><td>Answer a Rectangle that is the area in which the receiver overlaps with the argument, aRectangle.</td></tr><tr><td>merge: aRectangle</td><td>Answer the smallest Rectangle that contains both the receiver and the argument, aRectangle.</td></tr></table>

A ← 50@50 corner: 200@200.

B ← 120@120 corner: 260@240.

C ← 100@300 corner: 300@400.

<figure><img src="image_199.png" /><figcaption>Figure 18.11</figcaption></figure>
Then expressions using these three Rectangles are listed below. Notice that Rectangles print in the form `originPoint corner: cornerPoint`.

<table><thead><tr><td>expression</td><td>result</td></tr></thead><tbody><tr><td>A amountToTranslateWithin: C</td><td>50@250</td></tr><tr><td>A areasOutside: B</td><td>OrderedCollection ((50@50 corner: 200 @120) (50@120 corner: 120@200))</td></tr><tr><td>C expandBy: 10</td><td>90@290 corner: 310@410</td></tr><tr><td>C insetBy: 10@20</td><td>110@320 corner: 290@380</td></tr><tr><td>A intersect: B</td><td>120@120 corner: 200@200</td></tr><tr><td>B merge: C</td><td>100@120 corner: 300@400</td></tr></tbody></table>

The testing protocol for Rectangles includes messages to determine whether a Point or other Rectangle is contained within the boundaries of a Rectangle, or whether two Rectangles intersect.

Rectangle instance protocol

testing

<table><tr><td>contains: aRectangle</td><td>Answer whether the receiver contains all Points contained by the argument, aRectangle.</td></tr><tr><td>containsPoint: aPoint</td><td>Answer whether the argument, aPoint, is within the receiver.</td></tr><tr><td>intersects: aRectangle</td><td>Answer whether the receiver contains any Point contained by the argument, aRectangle.</td></tr></table>

Continuing the above example

<table><thead><tr><td>expression</td><td>result</td></tr></thead><tbody><tr><td>A contains: B</td><td>false</td></tr><tr><td>C containsPoint: 200@320</td><td>true</td></tr><tr><td>A intersects: B</td><td>true</td></tr></tbody></table>

Like the messages for a Point, the coordinates of a Rectangle can be rounded to the nearest integer. A Rectangle can be moved by some amount, translated to a particular location, and the coordinates can be scaled or translated by some amount. Rectangles also respond to scaling
and translating messages; they are part of the protocol for any object that can display itself on a display medium.

### Rectangle instance protocol

* truncation and round off
  rounded
  Answer a Rectangle whose origin and corner coordinates are rounded to the nearest integer.

* transforming
  moveBy: aPoint
  Change the corner positions of the receiver so that its area translates by the amount defined by the argument, aPoint.

moveto: aPoint
  Change the corners of the receiver so that its top left position is the argument, aPoint.

scaleBy: scale
  Answer a Rectangle scaled by the argument, scale, where scale is either a Point or a scalar.

translateBy: factor
  Answer a Rectangle translated by the argument, factor, where factor is either a Point or a scalar.

For example

<table><thead><tr><td>expression</td><td>result</td></tr></thead><tbody><tr><td>A moveBy: 50@50</td><td>100@100<br/>corner: 250@250</td></tr><tr><td>A moveto: 200@300</td><td>200@300<br/>corner: 350@450</td></tr><tr><td>A scaleBy: 2</td><td>400@600<br/>corner: 700@900</td></tr><tr><td>A translateBy: -100</td><td>100@200<br/>corner: 250@350</td></tr></tbody></table>

### Class BitBlt
The most basic interface to BitBlt is through a class of the same name. Each instance of BitBlt contains the variables necessary to specify a BitBlt operation. A specific application of BitBlt is governed by a list of parameters, which includes:

<table><tr><td>destForm</td><td>(destination form) a Form into which pixels will be stored</td></tr><tr><td>sourceForm</td><td>a Form from which pixels will be copied</td></tr><tr><td>halftoneForm</td><td>a Form containing a spatial halftone pattern</td></tr></table>
<table><tr><td>combinationRule</td><td>an Integer specifying the rule for combining corresponding pixels of the sourceForm and destForm</td></tr><tr><td>destX, destY, width, height</td><td>(destination area x, y, width, and height) Integers which specify the rectangular subregion to be filled in the destination</td></tr><tr><td>clipX, clipY, clipWidth, clipHeight</td><td>(clipping rectangular area x, y, width, and height) Integers which specify a rectangular area which restricts the affected region of the destination</td></tr><tr><td>sourceX, sourceY</td><td>Integers which specify the location (top left corner) of the subregion to be copied from the source</td></tr></table>

The BitBlt class protocol consists of one message for creating instances; this message contains a keyword and argument for each BitBlt variable. The BitBlt instance protocol includes messages for initializing the variables and a message, copyBits, which causes the primitive operation to take place. It also contains a message, drawFrom: startPoint to: stopPoint, for drawing a line defined by two Points.

BitBlt class protocol

<table><tr><td>instance creation</td><td></td></tr><tr><td>destForm: destination</td><td></td></tr><tr><td>sourceForm: source</td><td></td></tr><tr><td>halftoneForm: halftone</td><td></td></tr><tr><td>combinationRule: rule</td><td></td></tr><tr><td>destOrigin: destOrigin</td><td></td></tr><tr><td>sourceOrigin: sourceOrigin</td><td></td></tr><tr><td>extent: extent</td><td></td></tr><tr><td>clipRect: clipRect</td><td>Answer a BitBlt with values set according to each of the arguments, where rule is an Integer; destination, source, and halftone are Forms; destOrigin, sourceOrigin, and extent are Points; and clipRect is a Rectangle.</td></tr></table>

BitBlt instance protocol

<table><tr><td>accessing</td><td></td></tr><tr><td>sourceForm: aForm</td><td>Set the receiver's source form to be the argument, aForm.</td></tr><tr><td>destForm: aForm</td><td>Set the receiver's destination form to be the argument, aForm.</td></tr><tr><td>mask: aForm</td><td>Set the receiver's halftone mask form to be the argument, aForm.</td></tr><tr><td>combinationRule: anInteger</td><td>Set the receiver's combination rule to be the argument, anInteger, which must be an integer between 0 and 15.</td></tr><tr><td>clipHeight: anInteger</td><td>Set the receiver's clipping area height to be the argument, anInteger.</td></tr><tr><td>clipWidth: anInteger</td><td>Set the receiver's clipping area width to be the argument, anInteger.</td></tr></table>
<table><tr><td>clipRect</td><td>Answer the receiver's clipping rectangle.</td></tr><tr><td>clipRect: aRectangle</td><td>Set the receiver's clipping rectangle to be the argument, aRectangle.</td></tr><tr><td>clipX: anInteger</td><td>Set the receiver's clipping rectangle top left x coordinate to be the argument, anInteger.</td></tr><tr><td>clipY: anInteger</td><td>Set the receiver's clipping rectangle top left y coordinate to be the argument, anInteger.</td></tr><tr><td>sourceRect: aRectangle</td><td>Set the receiver's source form rectangular area to be the argument, aRectangle.</td></tr><tr><td>sourceOrigin: aPoint</td><td>Set the receiver's source form top left coordinates to be the argument, aPoint.</td></tr><tr><td>sourceX: anInteger</td><td>Set the receiver's source form top left x coordinate to be the argument, anInteger.</td></tr><tr><td>sourceY: anInteger</td><td>Set the receiver's source form top left y coordinate to be the argument, anInteger.</td></tr><tr><td>destRect: aRectangle</td><td>Set the receiver's destination form rectangular area to be the argument, aRectangle.</td></tr><tr><td>destOrigin: aPoint</td><td>Set the receiver's destination form top left coordinates to be the argument, aPoint.</td></tr><tr><td>destX: anInteger</td><td>Set the receiver's destination form top left x coordinate to be the argument, anInteger.</td></tr><tr><td>destY: anInteger</td><td>Set the receiver's destination form top left y coordinate to be the argument, anInteger.</td></tr><tr><td>height: anInteger</td><td>Set the receiver's destination form height to be the argument, anInteger.</td></tr><tr><td>width: anInteger</td><td>Set the receiver's destination form width to be the argument, anInteger.</td></tr><tr><td>copying</td><td></td></tr><tr><td>copyBits</td><td>Perform the movement of bits from the source form to the destination form. Report an error if any variables are not of the right type (Integer or Form), or if the combination rule is not between 0 and 15 inclusive. Try to reset the variables and try again.</td></tr></table>

The state held in an instance of BitBlt allows multiple operations in a related context to be performed without the need to repeat all the initialization. For example, when displaying a scene in a display window, the destination form and clipping rectangle will not change from one operation to the next. Thus the instance protocol for modifying individual variables can be used to gain efficiency.

Line Drawing

Much of the graphics in the Smalltalk-80 system consists of lines and text. These entities are synthesized by repeated invocation of BitBlt.
The BitBlt protocol includes the messages drawFrom: startPoint to: stopPoint to draw a line whose end points are the arguments, startPoint and stopPoint.

BitBlt instance protocol

line drawing

drawFrom: startPoint to: stopPoint

Draw a line whose end points are the arguments, startPoint and stopPoint. The line is formed by displaying copies of the current source form according to the receiver's half-tone mask and combination rule.

By using BitBlt, one algorithm can draw lines of varying widths, different halftones, and any combination rule. To draw a line, an instance of BitBlt is initialized with the appropriate destination Form and clipping rectangle, and with a source that can be any Form to be applied as a pen or "brush" shape along the line. The message drawFrom:to: with Points as the two arguments is then sent to the instance. Figure 18.12 shows a number of different pen shapes and the lines they form when the BitBlt combination rule is 6 or 7.

The message drawFrom: startPoint to: stopPoint stores the destX and destY values. Starting from these stored values, the line-drawing loop, drawLoopX: xDelta Y: yDelta, shown next, accepts x and y delta values and calculates x and y step values to determine points along the line, and then calls copyBits in order to display the appropriate image at each point. The method used is the Bresenham plotting algorithm (IBM Systems Journal, Volume 4, Number 1, 1965). It chooses a principal direction and maintains a variable, p. When p's sign changes, it is time to move in the minor direction as well. This method is a natural unit to be implemented as a primitive method, since the computation is trivial and the setup in copyBits is almost all constant from one invocation to the next.

The method for drawLoopX: xDelta Y: yDelta in class BitBlt is

drawLoopX: xDelta Y: yDelta

| dx dy px py p |

dx ← xDelta sign.

dy ← yDelta sign.

px ← yDelta abs.

py ← xDelta abs.

self copyBits. "first point"
<figure><img src="image_200.png" /><figcaption>Figure 18.12</figcaption></figure>

```pascal
py > px
ifTrue: "more horizontal"
[p - py // 2.
1 to: py do:
  [ :i | destx = destx + dx.
    (p = p - px) < 0
     ifTrue: [desty = desty + dy. p = p + py].
     self copyBits]]
ifFalse: "more vertical"
[p = px // 2.
1 to: px do:
  [ :i | desty = desty + dy.
    (p = p - py) < 0
     ifTrue: [destx = destx + dx. p = p + px].
     self copyBits]]
```
## Text Display

One of the advantages derived from BitBlt is the ability to store fonts compactly and to display them using various combination rules. The compact storage arises from the possibility of packing characters horizontally one next to another (as shown earlier in Figure 18.3), since BitBlt can extract the relevant bits if supplied with a table of left x coordinates of all the characters. This is called a *strike* format from the typographical term meaning a contiguous display of all the characters in a font.

The scanning and display of text are performed in the Smalltalk-80 system by a subclass of BitBlt referred to as CharacterScanner. This subclass inherits all the normal state, with destForm indicating the Form in which text is to be displayed and sourceForm indicating a Form containing all the character glyphs side by side (as in Figure 18.3). In addition CharacterScanner defines further state including:

<table><tr><td>text</td><td>a String of Characters to be displayed</td></tr><tr><td>textPos</td><td>an Integer giving the current position in text</td></tr><tr><td>xTable</td><td>an Array of Integers giving the left x location of each character in sourceForm</td></tr><tr><td>stopX</td><td>an Integer that sets a right boundary past which the inner loop should stop scanning</td></tr><tr><td>exceptions</td><td>an Array of Symbols that, if non-nil, indicate messages for handling the corresponding characters specially</td></tr><tr><td>printing</td><td>a Boolean indicating whether characters are to be printed</td></tr></table>

Once an instance has been initialized with a given font and text location, the scanWord: loop below will scan or print text until some horizontal position (stopX) is passed, until a special character (determined from exceptions) is found, or until the end of this range of text (endRun) is reached. Each of these conditions is denoted by a symbolic code referred to as stopXCode, exceptions (an Array of Symbols) and endRunCode.

### scanword: endRun

| charIndex |
|---|
| [textPos < endRun] whileTrue: |
| "pick character" charIndex ← text at: textPos. |
| "check exceptions" |
| (exceptions at: charIndex) > 0 |
| ifTrue: [↑exceptions at: charIndex]. |
| "left x of character in font" sourceX ← xTable at: charIndex. |
| "up to left of next char" |
| width ← (xTable at: charIndex + 1) - sourceX. |
| "print the character" printing ifTrue: [self copyBits]. |
```
"advance by width of character" destX ← destX + width.
destX > stopX if True: [1stopXCode]. "passed right boundary"
"advance to next character"
textPos ← textPos + 1.
textPos ← textPos - 1.
↑endRunCode
```

The check on exceptions handles many possibilities in one operation. The space character may have to be handled exceptionally in the case of text that is padded to achieve a flush right margin. Tabs usually require a computation or table lookup to determine their width. Carriage return is also identified in the check for exceptions. Character codes beyond the range given in the font are detected similarly, and are usually handled by showing an exceptional character, such as a little lightning bolt, so that they can be seen and corrected.

The printing flag can be set false to allow the same code to measure a line (break at a word boundary) or to find to which character the cursor points. While this provision may seem over-general, two benefits (besides compactness) are derived from that generality. First, if one makes a change to the basic scanning algorithm, the parallel functions of measuring, printing, and cursor tracking are synchronized by definition. Second, if a primitive implementation is provided for the loop, it exerts a threefold leverage on the system performance.

The scanword: loop is designed to be amenable to such primitive implementation; that is, the interpreter may intercept it and execute primitive code instead of the Smalltalk-80 code shown. In this way, much of the setup overhead for copyBits can be avoided at each character and an entire word or more can be displayed directly. Conversely, the Smalltalk text and graphics system requires implementation of only the one primitive operation (BitBlt) to provide full functionality.

## Simulation of BitBlt

We provide here a simulation of an implementation of copyBits in a subclass of BitBlt referred to as BitBltSimulation. The methods in this simulation are intentionally written in the style of machine code in order to serve as a guide to implementors. No attempt is made to hide the choice of 16-bit word size. Although the copyBits method is presented as a Smalltalk-80 method in BitBltSimulation, it is actually implemented in machine-code as a primitive method in class BitBlt; the simulation does the same thing, albeit slower.
<table><tr><td>class name</td><td>BitBitSimulation</td></tr><tr><td>superclass</td><td>BitBit</td></tr><tr><td>instance variable names</td><td>sourceBits sourceASTER<br/>destBits destASTER<br/>halftoneBits<br/>skew skewMask<br/>mask1 mask2<br/>preload nWords<br/>hDir vDir<br/>sourceIndex sourceDELTA<br/>destIndex destDELTA<br/>sx sy dx dy w h<br/>AllOnes RightMasks</td></tr><tr><td>class variable names</td><td>AllOnes RightMasks</td></tr><tr><td>class methods</td><td></td></tr></table>

initialize

"Initialize a table of bit masks"
RightMasks →
#(0 16r1 16r3 16r7 16rF
16r1F 16r3F 16r7F 16rFF
16r1FF 16r3FF 16r7FF 16rFFF
16r1FFF 16r3FFF 16r7FFF 16rFFFF).
AllOnes → 16rFFFF

instance methods

operations

copyBits

"sets w and h"
self clipRange.
(w <= 0 or: [h <= 0]) ifTrue: [↑self]. "null range"
self computeMasks.
self checkOverlap.
self calculateOffsets.
self copyLoop

private

clipRange

"clip and adjust source origin and extent appropriately"
"first in x"
destX >= clipX
ifTrue: [sx ← sourceX. dx ← destX. w ← width]
ifFalse: [sx ← sourceX + (clipX − destX).
          w ← width − (clipX − destX).
          dx ← clipX].
(dx + w) > (clipX + clipWidth)
ifTrue: [w ← w − ((dx + w) − (clipX + clipWidth))].
```
"then in y"
destY = clipY
    ifTrue: [sy ← sourceY. dy ← destY. h ← height]
    ifFalse: [sy ← sourceY + clipY - destY.
               h ← height - clipY + destY.
               dy ← clipY].
(dy + h) > (clipY + clipHeight)
    ifTrue: [h ← h - ((dy + h) - (clipY + clipHeight))].
sx < 0
    ifTrue: [dx ← dx - sx. w ← w + sx. sx ← 0].
sx + w > sourceForm width
    ifTrue: [w ← w - (sx + w - sourceForm width)].
sy < 0
    ifTrue: [dy ← dy - sy. h ← h + sy. sy ← 0].
sy + h > sourceForm height
    ifTrue: [h ← h - (sy + h - sourceForm height)]
```

Clipping first checks whether the destination x lies to the left of the clipping rectangle and, if so, adjusts both destination x and width. As mentioned previously, the data to be copied into this adjusted rectangle comes from a shifted region of the source, so that the source x must also be adjusted. Next, the rightmost destination x is compared to the clipping rectangle and the width is decreased again if necessary. This whole process is then repeated for y and height. Then the height and width are clipped to the size of the source form. The adjusted parameters are stored in variables sx, sy, dx, dy, w, and h. If either width or height is reduced to zero, the entire call to BitBlt can return immediately.

### computeMasks

```
| startBits endBits |
"calculate skew and edge masks"
destBits ← destForm bits.
destRaster ← destForm width - 1 // 16 + 1.
sourceForm notNil
    ifTrue: [sourceBits ← sourceForm bits.
              sourceRaster ← sourceForm width - 1 // 16 + 1].
halftoneForm notNil
    ifTrue: [halftoneBits ← halftoneForm bits].
skew ← (sx - dx) bitAnd: 15.
"how many bits source gets skewed to right"
startBits ← 16 - (dx bitAnd: 15).
"how many bits in first word"
mask1 ← RightMasks at: startBits + 1.
endBits ← 15 - ((dx + w - 1) bitAnd: 15).
"how many bits in last word"
mask2 ← (RightMasks at: endBits + 1) bitInvert.
```
skewMask ←
(skew = 0
    ifTrue: [0]
    ifFalse: [RightMasks at: 16 -- skew + 1]).
"determine number of words stored per line; merge masks if necessary"
w < startBits
    ifTrue: [mask1 ← mask1 bitAnd: mask2.
              mask2 ← 0.
              nWords ← 1]
    ifFalse: [nWords ← (w - startBits - 1) // 16 + 2].

In preparation for the actual transfer of data, several parameters are computed. First is skew, the horizontal offset of data from source to destination. This represents the number of bits by which the data will have to be rotated after being loaded from the source in order to line up with the final position in the destination. In the example of Figure 18.3, skew would be 5 because the glyph for the character "e" must be shifted left by 5 bits prior to being stored into the destination. From skew, skewMask is saved for use in rotating (this is unnecessary for machines with a rotate word instruction). Then mask1 and mask2 are computed for selecting the bits of the first and last partial words of each scan line in the destination. These masks would be 16r1FFF and 16rFFC0 respectively in the example of Figure 18.3 since startBits=13 and endBits=6. In cases such as this where only one word of each destination line is affected, the masks are merged to select the range within that word, here 16r1FC0.

### checkOverlap

| t |
"check for possible overlap of source and destination"
hDir ← vDir ← 1. "defaults for no overlap"
(sourceForm == destForm and: [dy > sy])
ifTrue:
    [dy > sy "have to start at bottom"
        ifTrue: [vDir ← -1. sy ← sy + h - 1. dy ← dy + h - 1]
        ifFalse: [dx > sx "y's are equal, but x's are backward"
                    ifTrue: [hDir ← -1.
                        sx ← sx + w - 1.
                        "start at right"
                        dx ← dx + w - 1.
                        "and fix up masks"
                        skewMask ← skewMask bitInvert.
                        t ← mask1.
                        mask1 ← mask2.
                        mask2 ← t]]]
A check must be made for overlapping source and destination. When source and destination lie in the same bitmap, there is the possibility of the copy operation destroying the data as it is moved. Thus when the data is being moved downward, the copy must start at the bottom and proceed upward. Similarly when there is no vertical movement, if the horizontal movement is to the right, the copy must start at the right and work back to the left. In all other cases the copy can proceed from top to bottom and left to right.

### calculateOffsets

```k
"check if need to preload buffer
(i.e., two words of source needed for first word of destination)"
preload ← (sourceForm notNil) and:
    [skew ~= 0 and: [skew <= (sx bitAnd: 15)]].
hDir < 0 ifTrue: [preload ← preload == false].
"calculate starting offsets"
sourceIndex ← sy * sourceRaster + (sx // 16).
destIndex ← dy * destRaster + (dx // 16).
"calculate increments from end of 1 line to start of next"
sourceDelta ←
    (sourceRaster * vDir) -
    (nWords + (preload ifTrue: [1] ifFalse: [0]) * hDir).
destDelta ← (destRaster * vDir) - (nWords * hDir)
```

In cases where two words of source are needed to store the first word into the destination, a flag preload is set indicating the need to preload a 32-bit shifter prior to the inner loop of the copy (this is an optimization; one could simply always load an extra word initially). The offsets needed for the inner loop are the starting offset in words from the source and destination bases; deltas are also computed for jumping from the end of the data in one scanline to the start of data in the next.

inner loop

### copyLoop

```k
| prevWord thisWord skewWord mergeMask
halftoneWord mergeWord word |
1 to: h do: "here is the vertical loop:"
    [ :i |
        (halftoneForm notNil)
        ifTrue:
            [halftoneWord ← halftoneBits at: (1 + (dy bitAnd: 15)).
             dy ← dy + vDir]
        ifFalse: [halftoneWord ← AllOnes].
        skewWord ← halftoneWord.
    ]
```
preload
  ifTrue: [prevWord ← sourceBits at: sourceIndex + 1.
    "load the 32-bit shifter"
    sourceIndex ← sourceIndex + hDir]
  ifFalse: [prevWord ← 0].

mergeMask ← mask1.

1 to to: nWords do: "here is the inner horizontal loop"
  [ :word |
    sourceForm notNil "if source is used"
    ifTrue:
      [prevWord ← prevWord bitAnd: skewMask.
      thisWord ← sourceBits at: sourceIndex + 1.
      "pick up next word"
      skewWord ←
        prevWord bitOr: (thisWord bitAnd: skewMask bitInvert).
      prevWord ← thisWord.
      skewWord ← (skewWord bitShift: skew) bitOr:
        (skewWord bitShift: skew - 16)].
      "16-bit rotate"
    mergeWord ← self merge: (skewWord bitAnd: halftoneWord)
      with: (destBits at: destIndex + 1).
  destBits
    at: destIndex + 1
    put: ((mergeMask bitAnd: mergeWord)
      bitOr: (mergeMask bitInvert
      bitAnd: (destBits at: destIndex + 1)).
  sourceIndex ← sourceIndex + hDir.
  destIndex ← destIndex + hDir.
  word = (nWords - 1)
  ifTrue: [mergeMask ← mask2]
  ifFalse: [mergeMask ← AllOnes].
  sourceIndex ← sourceIndex + sourceDelta.
  destIndex ← destIndex + destDelta]

The outer, or vertical, loop includes the overhead for each line, selecting the appropriate line of halftone gray, preloading the shifter if necessary, and stepping source and destination pointers to the next scanline after the inner loop. It should be noted here that the reason for indexing the halftone pattern by the destination y is to eliminate "seams" which would occur if the halftones in all operations were not coordinated this way.

The inner, or horizontal, loop picks up a new word of source, rotates it with the previous, and merges the result with a word of the destination. The store into the destination must be masked for the first and
last partial words on each scanline, but in the middle, no masking is re-
ally necessary.

merge: sourceWord with: destinationWord

"These are the 16 combination rules:"
combinationRule=0
  ifTrue: [↑0].
combinationRule=1
  ifTrue: [↑sourceWord bitAnd: destinationWord].
combinationRule=2
  ifTrue: [↑sourceWord bitAnd: destinationWord bitInvert].
combinationRule=3
  ifTrue: [↑sourceWord].
combinationRule=4
  ifTrue: [↑sourceWord bitInvert bitAnd: destinationWord].
combinationRule=5
  ifTrue: [↑destinationWord].
combinationRule=6
  ifTrue: [↑sourceWord bitXor: destinationWord].
combinationRule=7
  ifTrue: [↑sourceWord bitOr: destinationWord].
combinationRule=8
  ifTrue: [↑sourceWord bitInvert bitAnd: destinationWord bitInvert].
combinationRule=9
  ifTrue: [↑sourceWord bitInvert bitXor: destinationWord].
combinationRule=10
  ifTrue: [↑destinationWord bitInvert].
combinationRule=11
  ifTrue: [↑sourceWord bitOr: destinationWord bitInvert].
combinationRule=12
  ifTrue: [↑sourceWord bitInvert].
combinationRule=13
  ifTrue: [↑sourceWord bitInvert bitOr: destinationWord].
combinationRule=14
  ifTrue: [↑sourceWord bitInvert bitOr: destinationWord bitInvert].
combinationRule=15
  ifTrue: [↑AllOnes]

Efficiency
Considerations

Our experience has demonstrated the value of BitBlt's generality. This
one primitive is so central to the programming interface that any im-
provement in its performance has considerable effect on the interactive
quality of the system as a whole. In normal use of the Smalltalk-80 sys-
tem, most invocations of BitBlt are either in the extreme microscopic or
macroscopic range.