If the initial click identifies a legal piece but the destination square is illegal, the attempted move is also ignored. Illegal moves include an attempt to move to a position occupied by one's own piece, moving to a position outside the legal path of the piece or identical to the starting position, and moves along an obscured path (legal knight moves are an exception). A move that exposes one's own king to check is also illegal.

More complicated moves including castling (a move involving a king and a rook), pawn capturing, and pawn replacement upon reaching the opponent's end of the board are not supported. Check mates are recognized only implicitly in that no legal move is possible from a check mate position. Draws are not recognized. When a move results in a check of the opponent's king, the program displays a warning and a red CHECK label. The game ends when a player clicks *End of game*. The *Help* buttons explains the use of the program.

### Scenarios.

In keeping with the specification, the term *Player* used in the following scenarios denotes a human player.

#### Scenario 1: Starting a game between two human players.

1. *Player* executes a statement such as `Chess open`.

2. *Program* opens board in the state shown in Figure A.3.1, expecting white to make the first move. When the player moves the cursor to the chessboard, it takes the shape of a W indicating that it is the white's turn to play.

#### Scenario 2. Making a legal move.

1. *Player* clicks one of his or her pieces.

2. *Program* changes cursor to a D, to indicate that the player should click the destination square.

3. *Player* clicks a legal destination square.

4. *Program* redisplays the affected squares.

5. *Program* changes cursor to a W or a B depending on which player moves next.

#### Scenario 3. Making a legal move resulting in a check.

Same as Scenario 2 but at the end, *Program* displays a dialog warning about the check and the word `CHECK` in red letters in the game window. The word is removed when the player makes a move that eliminates the check.

#### Scenario 4. Making an illegal move: First click is an empty square or square occupied by opponent's piece.

1. *Player* clicks an empty square. The shape of the cursor does not change and the click is ignored. The next click is considered to be the first click.

#### Scenario 5. Making an illegal move: Desired destination is occupied by one's own piece, a piece is blocking the path, the desired move leaves player's king in check, the destination is not on a legal path or is identical to the starting position.

1. *Player* clicks one of his or her pieces.

2. *Program* changes cursor to a D.

3. *Player* clicks a square occupied by his or her own piece.

4. *Program* does not change the chess board and redisplays the initial cursor (B or a W) allowing the player to make a new move.

#### Scenario 6. *End of game* by clicking *End of game*.

1. *Player* clicks *End of game*.

2. *Program* displays multiple choice dialog with *Quit*, *New game*, and *Cancel* buttons.

3. *Player* clicks *Quit* and closes the program.
## Context Diagram

The major components of the system are the chess board with its pieces and user interface, and the players. The players (including a computer program player) are outside of the scope of the task. The Context Diagram is shown in Figure A.3.2.

<figure><img src="image_303.png" /><figcaption>Figure A.3.2. Context Diagram showing components to be designed and components outside the scope of the task.</figcaption></figure>

## A.3.2 Preliminary Design

### Candidate classes

From the specification, our understanding of chess, and our knowledge of the principles of VisualWorks interfaces we decide on the following candidate classes:

**ChessBoard.** Domain model of the chess board. Knows the occupant of each square, and which player will move next. Can determine whether a move is legal or not in collaboration with individual pieces.

**King.** Knows its position and color, helps to determine whether an attempt to move it is legal. Domain class. Knows its graphical representation.

**Queen, Bishop, Knight, Rook, Pawn.** Same responsibilities as King but different operation. Domain classes.

**ChessGame.** Application model defining the window and interfacing the GUI with the domain model.

**ChessView.** Displays the board and knows how to redraw itself or its parts in response to a new **ChessBoard** state. A UI class.

**ChessController.** The controller of **ChessView**. Captures mouse clicks and converts them to appropriate actions resulting in changes of **ChessBoard**, and piece positions. Controls cursor image.

### Class-level scenarios

After identifying the candidates, we will now examine the scenarios at class-level detail to determine class responsibilities and confirm that we have all the classes we need.
### Scenario 1. Starting a game.

1. Player executes Chess open.

2. ChessGame initializes its instance variables, opens board in starting state, expecting the first move to be made by white. ChessController displays a W shaped cursor.

### Scenario 2. Making a legal move.

1. Player clicks one of his or her pieces.

2. ChessController converts cursor coordinates to square row and column, requests confirmation that this is a legal square from ChessBoard, and changes cursor to a D.

3. Player clicks a legal destination square.

4. ChessController converts cursor coordinates to square coordinates, asks ChessBoard to confirm and perform the move. ChessBoard performs the necessary tests, asking the selected piece to execute piece-related actions. It asks ChessView to redisplay the current square as empty and display the moved piece in the new position. If the new position was occupied by an opponent's piece, it removes the opponent's piece from the game. ChessGame changes cursor to W or B depending on the player whose turn it is next.

Scenarios 3, 4, and 5 follow the same pattern as Scenario 2 and we leave them as exercises. Scenario 6 does not require any further comments and we can now construct the following preliminary class descriptions:

### Preliminary class descriptions

**Chess.** Application model implementing the main user interface.

**Components:** chessBoard, chessView

**Responsibilities:**

* opening - start new game and display user interface

* accessing - chess view

* action methods - buttons

* help - display help window

* end of game - display dialog and close if required

**Collaborators**

* ChessBoard, ChessView

* chess pieces

* ChessView

**ChessBoard.** Domain model of the chess board.

**Components:** squares (TwoDList), currentPlayer (Symbol)

**Responsibilities:**

* initialization

* accessing - pieces, view (via dependency)

* making a move and alternating players

* testing legality of moves and checks

**Collaborators**

* pieces

* pieces

* pieces

**ChessController.** Captures mouse clicks, controls cursor.

**Components:** firstClick (Boolean), currentCursor, blackCursor, whiteCursor, destCursor

**Responsibilities:**

* initialization - define cursor shapes and control current cursor

* events - tracking mouse position and button action

* control of cursor shape

**Collaborators**

**ChessView.** Display of the chess board.

**Components:**

**Responsibilities:**

* displaying chessboard with pieces

* updating - response to ChessBoard changes via dependency

* controller access

**Collaborators**

* ChessBoard and pieces

* ChessBoard

* ChessController
Bishop, King, Knight, Rook, Pawn, Queen - represent individual pieces.

Components: color, position

Responsibilities:

* testing - is proposed move legal?

* visual representation – image of black and white pieces on both backgrounds

From this specification, we can draw the preliminary Object Model in Figure A.3.3.

Collaborators

<figure><img src="image_304.png" /><figcaption>Figure A.3.3. Preliminary Object Model.</figcaption></figure>

### A.3.3 Design Refinement

We will now identify abstract classes and the superclass of each class, create a Class Hierarchy diagram, refine responsibilities, and finalize the Object Model.

Abstract classes

The different pieces share a lot of information and behavior: Each has a color and a position on the chess board, all participate in the testing of the legality of a move, and all have their visual representation. We will thus create an abstract class called Piece to define all the common behavior. Class Piece itself is unique and its superclass will thus be Object.

Classes ChessView and ChessController are, of course, in the View and Controller hierarchies. ChessView will be a subclass of View, and ChessController will be a subclass of Controller because we need event notification but no menu.

Class ChessBoard treats ChessView as its dependent and its superclass is thus Model.

Results of this analysis are summarized in the Class Hierarchy diagram in Figure A.3.4 and the following table.

<figure><img src="image_305.png" /></figure>
Figure A.3.4. Class Hierarchy. Classes in heavy rectangles are to be implemented.

Class Characteristics:

<table><thead><tr><td>Class</td><td>Type</td><td>Superclass</td><td>Comment on the choice of superclass</td></tr></thead><tbody><tr><td>Chess</td><td>concrete</td><td>ApplicationModel</td><td>Mediator between domain model (board and pieces) and GUI.</td></tr><tr><td>ChessBoard</td><td>concrete</td><td>Model</td><td>We need dependency to control ChessView.</td></tr><tr><td>ChessController</td><td>concrete</td><td>Controller</td><td>Controller provides behaviors such as events, and access to view.</td></tr><tr><td>ChessView</td><td>concrete</td><td>View</td><td>View provides persistence and dependency mechanism.</td></tr><tr><td>Piece</td><td>abstract</td><td>Object</td><td>There is no suitable superclass in the hierarchy.</td></tr><tr><td>King</td><td>concrete</td><td>Piece</td><td>Piece was created as an abstraction of individual pieces.</td></tr><tr><td>Queen</td><td>concrete</td><td>Piece</td><td>Same comment.</td></tr><tr><td>Bishop</td><td>concrete</td><td>Piece</td><td>Same comment.</td></tr><tr><td>Knight</td><td>concrete</td><td>Piece</td><td>Same comment.</td></tr><tr><td>Rook</td><td>concrete</td><td>Piece</td><td>Same comment.</td></tr><tr><td>Pawn</td><td>concrete</td><td>Piece</td><td>Same comment.</td></tr></tbody></table>

### Details of selected behaviors

We will now explore and describe, class by class, the more complicated behaviors in order to obtain sufficiently detailed class descriptions suitable for implementation.

#### Class Chess

The application opens in the usual way and executes the initialization method. Initialization must create a new `ChessBoard` and a new `ChessView`, and assign the `ChessBoard` to the view as its model. Class `ChessBoard` must be able to modify information such as the name of current player and this requires that the creation method of `Chess` provide `Chess` with access to `ChessBoard`.

The essence of the program is moving pieces. Every move is initiated by a mouse click, mouse clicks are intercepted by the controller, and we will thus continue with the controller.

#### Class ChessController

The controller responds to button clicks and controls the cursor via methods with predefined event selectors `redButtonActivity:`, `enterEvent:`, and `exitEvent:`. Message `redButtonActivity:` is sent when the user clicks the red button to select a piece or a destination and its implementation will be as follows:

- Calculate square in row/column coordinates. This is needed to access a piece in `ChessBoard`.

- If this is the first click of the current player then

- ask `ChessBoard` whether the square is a legal starting point

- remember that the next click will be the second click

- change cursor shape to D

- If this is not the first click then

- notify `ChessBoard` of the destination square

- ask `ChessBoard` to make move if it is legal

- remember that next move will be the first move (even if the move was illegal)

- if the move was legal, change current player and change cursor to W or B

We will now follow the task of moving a piece by exploring `ChessBoard`'s role in this process. We will return to the controller later.
### Class ChessBoard

ChessBoard is responsible for intialization, tests and for triggering the display of the new state.

* Variable squares is initialized to empty squares or to appropriate pieces. The rest is obvious.

* The test of whether the starting position is legal checks that the square contains a piece belonging to the current player. If it does not, the move is illegal.

* Our implementation of the test of the destination and the subsequent move will be as follows:

* Check if the destination square is legal (empty square or square with opponent's piece)

* Check if the piece can reach the destination. The move is possible if

* the piece can reach the destination without considering possible obstructions

* the path from start to destination is not obstructed (except for the knight)

* Move piece tentatively to the new position without redrawing the board

* Check whether the move uncovers current player's king. (To do this, opponent's pieces check whether they can reach the king.) If everything is OK, display new position using dependency of ChessView on ChessBoard, otherwise ignore the move.

* Is opponent's king in check (player's pieces test whether they can reach opponent's king)? If so, display warning and red label.

To make the operation and design more efficient, we will add the following behaviors and instance variables:

* A method to check whether a move is horizontal, vertical, diagonal, or other ('illegal') because one or more of these tests are required by most pieces. The result is stored in variable kindOfMove.

* Instance variables kings for quick access to the king piece for tests of checks, and blackPieces and whitePieces - again to speed up tests of checks.

### Class ChessController

We can now return to ChessController and describe the details of its responsibilities.

* Initialization (occurs automatically when the controller is created): firstClick becomes true, cursor becomes the W cursor because the white player moves first.

* Response to enterEvent which is sent when the cursor enters this controller's view: Remember old cursor (to be displayed when the cursor leaves ChessView) and change cursor to its proper value.

* Response to exitEvent which is sent when the cursor leaves ChessView: Reset cursor to what it was before the cursor entered the chess view.

We conclude that the controller must remember the current and old cursors, and the three cursor images (W, B, and D). To construct them, we will use the Image Editor tool, remembering to keep the image to 16@16 pixels, the prescribed Cursor extent.

### Class ChessView

Class ChessView is responsible for drawing the chess board at the beginning of a new game, updating it after a legal move, and redrawing it after damage. As we know, this is implemented by displayOn: and update.

Method displayOn: goes through all 64 squares of the chess board. It displays a black or a white square when the square is empty, and if the square contains a piece, asks the piece for the appropriate image and displays it.

Updating is invoked after a move, when ChessBoard issues a changed message. Since each move in this pilot implementation changes only the origin and the destination, we will restrict the response to an update of just those two squares. To be able to do this, we will use update:with: and supply the two squares as an Array argument of the with: keyword.
### Class Piece

This class defines shared behaviors and variables of concrete pieces such as King and Queen. The responsibility for testing whether a move can be made is left to concrete subclasses because each concrete subclass uses a different rule. Responsibility for accessing is implemented here.

This completes our design except for the concrete pieces. For a Bishop, legal moves are diagonal. For a Rook, a legal move is either vertical or horizontal. For a Queen, any move that is not classified as 'illegal' is legal; this includes horizontal, vertical, and diagonal moves. Legal moves for Pawn and Knight require special treatment.

The image of a piece is implemented as a class 'resource' method compiled by the Image Editor. These cached images will be used as required.

We will now update our class descriptions, restricting ourselves to a new listing of variables. We don't preclude the possibility that we may have to add auxiliary instance variables during implementation to improve efficiency or to cover any gaps that may still be present.

### Updated class descriptions

#### Class Chess

Instance variables: chessBoard, chessView.

#### Class ChessBoard

Instance variables: squares, kings, kindOfMove, blackPieces, whitePieces, currentPlayer, oldPosition, newPosition, removedPiece (needed when restoring a tentatively moved piece when the move is illegal).

#### Class ChessController

Instance variables: firstClick, oldCursor, currentCursor, blackCursor, destCursor, whiteCursor.

#### Class ChessView

Instance variables: none.

#### Class Piece

Instance variables: color, position.

#### Class Bishop and other concrete pieces

Instance variables: none.

### Object Model diagram

To complete design, we update the Object Model diagram as in Figure A.3.5.
<figure><img src="image_306.png" /><figcaption>Figure A.3.5. Object Model diagram of chess game classes.</figcaption></figure>

### A.3.4 Implementation

Most of the implementation is straightforward and we will limit ourselves to the less trivial methods. The presentation will be organized by class, and classes will be listed alphabetically.

#### Class Bishop

The creation message for all pieces is color: aColorValue position: aPoint and is defined in class Piece. Besides the resource methods that define bishop's image, the only protocol defined in this class is testing of a legal move. The test checks that the requested move is diagonal as follows:

**legalMove: kindOfMove to: aPoint**

"Return true if this piece can move to this destination."

^kindOfMove == #diagonal

where kindOfMove is a Symbol calculated by ChessBoard when the player makes a move. As you can see, its use considerably simplifies the test. The argument aPoint is necessary for pieces such as the knight and since the legalMove:to: message is used polymorphically by all pieces, both arguments must be included even when they are not always needed.

#### Class Chess

is the application model and its opening message initializes the program as follows:

**initialize**

chessBoard := ChessBoard newFrom: self. "Let ChessBoard know about myself for accessing."

chessView := ChessView new initialize.

chessView model: chessBoard

After a player makes a move, ChessBoard switches players and sends the following message to change the player label in the window.

**player: aPlayer**

"Players switched. Assign player and display color label on the UI, hiding the other label."

| otherPlayer |
```kts
otherPlayer := aPlayer == #white
    ifTrue: [#black]
    ifFalse: [#white].
(self builder componentAt: otherPlayer) beInvisible.
(self builder componentAt: aPlayer) beVisible
```

The operation is based on our decision to paint all possible labels on the canvas and display and hide them selectively as needed.

### Class ChessBoard

Holds board information and needs to know about Chess to notify it to update display after a move has been made.

### initializeFrom: app

```
"Initialize everything for the first game."
    appModel := app.
    self newGame
```

The lengthy code that initializes the squares and creates pieces is taken out into the following methods:

### newGame

```
"Initialize square information and create white and black pieces."
    self initializeSquares.
    self initializePieces.
    currentPlayer := #white
```

Method newGame: is reused as a response to the selection New game in the closing dialog of the game. The details of initialization are as follows:

### initializeSquares

```
"Create holder for board description and assign a piece to each square."
    | pos |
    squares := TwoDList columns: 8 rows: 8.
    1 to: 8 do: [:col | "Blank empty squares."
        1 to: 8 do: [:row | squares at: row @ col put: nil]].
    1 to: 8 do: [:col | "Place remaining pieces."
        "Place pawns."
        squares at: (pos := col @ 2) put: ( color: #black position: pos).
        squares at: (pos := col @ 7) put: (Rook color: #white position: pos).
        "Place all remaining pieces."
        squares at: (pos := 1 @ 1) put: (Rook color: #black position: pos).
        squares at: (pos := 1 @ 8) put: (Rook color: #white position: pos).
        squares at: (pos := 8 @ 1) put: (Rook color: #black position: pos).
        squares at: (pos := 8 @ 8) put: (Rook color: #white position: pos).
        squares at: (pos := 2 @ 1) put: (Knight color: #black position: pos).
        squares at: (pos := 2 @ 8) put: (Knight color: #white position: pos).
        squares at: (pos := 7 @ 1) put: (Knight color: #black position: pos).
        squares at: (pos := 7 @ 8) put: (Knight color: #white position: pos).
        squares at: (pos := 3 @ 1) put: (Bishop color: #black position: pos).
        squares at: (pos := 3 @ 8) put: (Bishop color: #white position: pos).
        squares at: (pos := 6 @ 1) put: (Bishop color: #black position: pos).
        squares at: (pos := 6 @ 8) put: (Bishop color: #white position: pos).
        squares at: (pos := 4 @ 1) put: (Queen color: #black position: pos).
        squares at: (pos := 4 @ 8) put: (Queen color: #white position: pos).
        squares at: (pos := 5 @ 1) put: (King color: #black position: pos).
        squares at: (pos := 5 @ 8) put: (King color: #white position: pos)
```

Auxiliary variables holding white pieces, black pieces, and kings are initialized as follows:
initializePieces

"Initialize variables holding black pieces, white pieces, and kings using information about squares."

whitePieces := OrderedCollection new: 16.

blackPieces := OrderedCollection new: 16.

kings := Array new: 2.

squares do: [:piece | piece isNil

ifFalse: [piece color == #white

ifTrue: [whitePieces add: piece.

piece isKing ifTrue: [kings at: 1 put: piece]]

ifFalse: [blackPieces add: piece.

piece isKing ifTrue: [kings at: 2 put: piece]]]

The essence of the program is the handling of individual moves and besides the necessary manipulation of the user interface, this requires various checks. The method is implemented as follows:

move

"Attempt to make a move and return true if the move is legal. Do nothing and return false otherwise."

| piece destPiece |

piece := squares at: oldPosition. "Piece at first click position."

"Move is legal only if destination is empty or occupied by opponent."

((destPiece := squares at: newPosition) isNil or: [destPiece color ~ currentPlayer])

ifFalse: [^false].

"Can this piece go to the specified destination?"

(self piece: piece canReach: newPosition from: oldPosition)

ifFalse: [^false].

"Make the move tentatively."

self move: piece to: newPosition.

"Does the move leave the player's king exposed? If so, retract."

self inCheck ifTrue: [self restore: piece. ^false].

(appModel builder componentAt: #check) beInvisible.

"Move is OK, get it displayed via dependency."

self changed: #position with: (Array with: oldPosition with: newPosition).

"Does the move put opponent's king in check? Display red label if true."

self checks ifTrue: [(appModel builder componentAt: #check) beVisible].

"Move completed, get ready for next player's move."

self switchPlayer.

^true

Although this method works correctly, it's design is unsatisfactory. In particular, ChessBoard is a
domain object and its implementation should be independent of the user interface. Yet, this method directly
accesses a specific component of the user interface – the check label. If the interface changed, this
reference would become invalid, and if we wanted to use ChessBoard in another application, we couldn't.
The proper way for a domain object to communicate with the UI is by notifying the application model of
the change that occurred and leave the implementation details to it. We leave this modification as an
exercise.

As you have noticed, the move method performs a variety of tests and some of them were
delegated to the following auxiliary methods:

piece: aPiece canReach: point2 from: point1

"Can aPiece go from point1 to point2?"

"Determine the kind of move (such as horizontal or vertical) being attempted."

self kindOfMoveFrom: point1 to: point2.

"Ask the piece if this move is OK.

(aPiece legalMove: kindOfMove to: point2)

ifFalse: [^false].

"Move is OK but is the path clear?"

^self isClearFrom: point1 to: point2

In here, method legalMoveFrom:to: checks whether aPiece can, in principle, move from point1 to
point2. It does not check whether the path is clear. The method is defined differently for each piece because
it depends on how the piece moves. We saw how Bishop treats legalMoveFrom:to: and other pieces define it similarly. Message isClearFrom:to: is sent only after confirmation that the move is, in principle, legal; it checks whether the path between the two points is clear and its definition is as follows:

### isClearFrom: point1 to: point2

"Return true if the path from point1 to point2 is clear. Delegate the problem to specialized direction-dependent methods."

kindOfMove == #horizontal ifTrue: [^self horizontalClearFrom: point1 to: point2].

kindOfMove == #vertical ifTrue: [^self verticalClearFrom: point1 to: point2].

kindOfMove == #diagonal ifTrue: [^self diagonalClearFrom: point1 to: point2].

^true "Knight does not care about obstructions."

The method uses specialized methods that test a horizontal path, a vertical path, and a diagonal path. We could reduce the number of tests somewhat but the definition would be less readable and we thus leave it in this form. The following is an implementation of one of these test methods:

### horizontalClearFrom: point1 to: point2

"Return true if the horizontal line between the two points is clear."

| x1 x2 y step |

x1 := point1 x.

x2 := point2 x.

y := point1 y.

x1 > x2 ifTrue: [step := -1]

ifFalse: [step := 1].

x1 + step to: x2 - step by: step do: [:x | (squares at: x @ y) isNil ifFalse: [^false]].

^true

The method that determines the kind of move is defined as follows:

### kindOfMoveFrom: point1 to: point2

"Is the move horizontal, vertical, diagonal, or 'illegal'? Return appropriate symbol."

kindOfMove := point1 y = point2 y

ifTrue: [#horizontal]

ifFalse: [point1 x = point2 x

ifTrue: [#vertical]

ifFalse: [(point1 x - point2 x) abs = (point1 y - point2 y) abs

ifTrue: [#diagonal]

ifFalse: [#illegal]]]

The chessboard knows about all pieces and so we leave it in charge of king checks. One such check requires finding whether a piece in a new position checks the opponent's king, the other checks whether it uncovers the player's own king to check. Both tests work on the same principle. As an example, the test to determine whether a move leaves the player's king in check is defined as follows:

### inCheck

"Test whether the king of the current player is in check by asking each opponent piece. Return true if check."

| position |

position := self myKing position.

"Ask each of the opponent's pieces if it can reach the king."

self opponentPieces do: [:piece | (self

piece: piece

canReach: position

from: piece position)

ifTrue: [^true]].

^false

Finally, the following method restores the chess board to its original position if we must take back a tentative move that resulted in a check to one's own king:
### restore: aPiece

"Attempted move is illegal because it exposes my king to check. Restore original state of board domain model. No need to redraw because we have not drawn anything yet."

"Move piece to its original position."

squares at: oldPosition put: aPiece.

"Restore taken piece if any."

removedPiece isNil ifFalse: [self opponentPieces add: aPiece].

squares at: aPiece position put: removedPiece.

aPiece position: oldPosition

### Class ChessController

This class is in charge of user interaction for the chess view. Its initialization method prepares the controller for the first click and defines the three cursor shapes:

### initialize

firstClick := true.

whiteCursor := Cursor

image: ChessController aWhiteCursor asImage

mask: ChessController aWhiteCursorMask asImage

hotSpot: 4 @ 8

name: 'white moves'.

blackCursor := Cursor

image: ChessController aBlackCursor asImage

mask: ChessController aBlackCursorMask asImage

hotSpot: 4 @ 8

name: 'black moves'.

destCursor := Cursor

image: ChessController aDestCursor asImage

mask: ChessController aDestCursorMask asImage

hotSpot: 4 @ 8

name: 'destination'.

currentCursor := whiteCursor

The 'resource' class methods aWhiteCursor, aBlackCursor, and aDestCursor supply the cursor. They were generated automatically by painting the image and mask shapes by the Image Editor. Note that the image and the mask are stored by two different commands (Figure A.3.6).

<figure><img src="image_307.png" /><figcaption>Figure A.3.6. Image Editor allows installing a shape as a cached image or as a mask.</figcaption></figure>

Cursor control methods are implemented by the predefined event selectors as follows:

### enterEvent: event

"Remember cursor on entry and switch to the cursor appropriate for the current state."

oldCursor := Cursor currentCursor.

Cursor currentCursor: currentCursor.

currentCursor show

### exitEvent: event

"Return to the saved cursor."
Cursor currentCursor: oldCursor.
Cursor normal show

The calculation of currentCursor occurs when the mouse button is clicked and is explained below.

The activity associated with pressing the <select> button when the player selects a piece or a
destination again uses a predefined event selector. It is defined as follows:

redButtonPressedEvent: event

"User clicked <select> button over a square. Relate this to the move now in progress."

| square |

"Convert cursor coordinates to row and column numbers."

square := ((self sensor cursorPointFor: event) / self view squareExtent) truncated + (1 @ 1).

firstClick ifTrue: "First click selects piece. Check legality, notify ChessBoard, change cursor."

[(self model isSquareLegal: square)
 ifFalse: [^self].
 self model oldPosition: square. "Remember old position to be able to restore it."
 firstClick := false.
currentCursor := destCursor]
ifFalse: "Second click selects destination. Check, make move, change cursor."
 [self model newPosition: square.
 self model move.
 firstClick := true.
currentCursor := self model currentPlayer == #white
 ifTrue: [whiteCursor]
 ifFalse: [blackCursor]].

"Ask new cursor to display itself."
currentCursor show

Class ChessView

The main responsibility of this class is, of course, displaying. The displayOn: method is automatically executed for every damage and change, and during opening. It must be able to redraw the whole board and we implement it by enumerating over all squares, displaying squares for the empty ones, and asking occupying pieces to supply their image for the given background (explained later). The definition is as follows:

displayOn: aGraphicsContext

"Draw the board for the current configuration of pieces."
squareExtent := self squareExtent. "Get the extent of a square in pixels."

1 to: 8 do: [:row | 1 to: 8

do: [:column |
    | background piece square |
    "Calculate view coordinates of square from its row and column numbers."
    square := column - 1 * squareExtent @ (row - 1 * squareExtent).
    "Calculate background color."
    background := (row + column) even
        ifTrue: [#white]
        ifFalse: [#lightGray].
    piece := self model squares at: column @ row. "Piece on current square, if any."
    piece isNil
        ifTrue: "The square is empty."
            [aGraphicsContext paint: (ColorValue perform: background);
             displayRectangle: (0 @ 0 extent: squareExtent @ squareExtent)
                 at: square]
        ifFalse: "The square contains a piece. Get its image from the piece."
            [aGraphicsContext displayImage:
                (piece imageForPlayer: piece color
                 onBackground: background)
                at: square]]
Note that we added a new instance variable called `squareExtent` to hold the size of a square. Its value will be useful for updating as well and `Chess` calculates it from the actual window size using lazy evaluation because during initialization, the chess board view has not yet been built. Alternatively, we could do the calculation in `postBuildWith:`.

Another responsibility of the view is response to update requests. The `update` method is executed whenever `ChessBoard` (the model of `ChessView`) executes the changed message which happens when it accepts a legal move. We use the `update:with:` form because the model (a `ChessBoard`) must supply the two `Rectangle` objects corresponding to the squares that are to be redrawn. The implementation is as follows:

**update: aSymbol with: anArray**

"The model has changed. Invalidate the affected squares."

| square |
1 to: 2 do: [:i | square := anArray at: i.
self invalidateRectangle: (square - 1 * squareExtent extent: squareExtent)]

Note that we restrict invalidation to the two affected squares. Although this does not speed up redrawing, it eliminates flashing which would occur if the whole board was redrawn.

### Class Knight

Like all other pieces, Knight only defines its shape and a test for a legal move. The definition is as follows:

**legalMove: kindOfMove to: aPoint**

"Return true if this piece can move to aPoint. Two vertical steps and one horizontal step or vice versa are legal."

| absX absY |
absX := (position x - aPoint x) abs.
absY := (position y - aPoint y) abs.
kindOfMove == #illegal "#horizontal, #vertical, and #diagonal, are disallowed for kinghts."
ifTrue: [^(absX = 2 and: [absY = 1])
    or: [absX = 1 and: [absY = 2]]].
^false

### Class Piece

This class is used mainly for shared variables and does not define any interesting methods, except for the creation method

**color: aSymbol position: aPoint**

^(self new) color: aSymbol; position: aPoint

calculation of the piece image to display for the current player

**imageForPlayer: symbol1 onBackground: symbol2**

^(self class imageForPlayer: symbol1 onBackground: symbol2) asImage

where

**imageForPlayer: symbol1 onBackground: symbol2**

"Retrieve the appropriate image for this piece and for the current player."

```
^self perform: (symbol1 == #white
    ifTrue: [symbol2 == #white
        ifTrue: [#whiteOnWhite]
        ifFalse: [#whiteOnBlack]]
    ifFalse: [symbol2 == #white
        ifTrue: [#blackOnWhite]
        ifFalse: [#blackOnBlack]])
```
and method isKing which defines every piece not to be a King by default. (Method isKing is used to assemble the array of kings.) The definition is listed below and only class King redefines it to return true. This is a typical trick used to eliminate multiple definitions when only one class has a different implementation, and method isNil is an example of a library method defined in this way.

isKing

^false

These selected methods should give you a good idea of our implementation and we leave the rest and improvements to you as exercises.

Main lessons learned:

* A cursor may be constructed with the Image Editor. Remember that cursor size is limited to 16@16 and that the mask shape must be stored as a mask.

* Redrawing should always be restricted to a minimum to minimize flashing. This can be achieved by using `invalidateRectangle:` instead of `invalidate`. In some situations, one can also design `displayOn:` to redraw only the required part of the view.

* Smalltalk normally leaves damage repair by invalidation until the processor has nothing more important to do (lazy invalidation). To redisplay without delay, use `invalidateRectangle:repairNow:`.

Exercises

1. Complete and test the implementation.

2. Redesign the application by introducing a new class called `Move` with components `kindOfMove` (a `Symbol`) and `startSquare` and `endSquare` (both `Points`). Consider implementing squares as instances of `BoardSquare` capable of displaying themselves and knowing their chess piece.

3. Implement all rules of chess such as castling, taking en passant, and so on. Does this extension require a major change in the original design?

4. We have seen that illegal situations such as division by zero are generally handled by the exception mechanism. Give a detailed description of how illegal moves could be handled as exceptions.

5. Remove the direct coupling between the domain model `ChessBoard` and the user interface.

6. Moving a piece takes a noticeable time in the current implementation. When you analyze what is happening, you will find that although we limit display to only two squares (using `invalidateRectangle:`), the whole `displayOn:` method must still be executed and all 64 squares recalculated. It seems that performance could be improved by making sure that only the two affected pieces are re-evaluated. Estimate how much this modification could speed up redisplay and implement it.

7. Measure how long it takes to draw the interface for various drawing strategies including `invalidate`, `invalidateRectangle:`, and the improvement suggested in the previous exercise. Compare the seriousness of flashing of the various approaches.

8. How would our implementation have to be modified if we wanted to use it as the interface of a computer player?

9. Improve the game by allowing players to initiate an automatic log of their moves. Allow the game log to be printed or replayed under the control of an additional button. Keep names and scores of players.

10. Enforce a time limit on each move. When a move is not completed within the limit, the player automatically loses the game.

11. Write a series of simple computer chess player programs starting with a program that makes random moves.

12. Use or modify suitable parts of the chess program to answer the following question:

i. Which positions can be reached by a knight from a given starting position in exactly three moves?

ii. Which positions can be reached by a knight from a given starting position in at most three moves?
iii. How many moves are required for a knight to reach a given square from a given starting square?

iv. What is the maximum number of moves for a knight to reach any position on the board from a given starting square?

v. Find a configuration of eight queens such that none can reach any other in one move. This problem is called the problem of eight queens.

vi. Find all queen positions for the previous exercise.

Conclusion

In this appendix, we presented the complete development of an application with a custom user interface component. The notable features were the creation of custom cursors and handling of input events. We also used view invalidation restricted to a small part of the view and mentioned that although this does not speed up display, it minimizes flashing and thus improves the quality of the user interface.
# Appendix 4 - Classes, Metaclasses, and Metaprogramming

## Overview

This chapter examines the ultimate question - the nature of classes. As we know, everything in Smalltalk is an instance of a class and this applies even to classes themselves. We will see that every class is an instance of a metaclass and that the hierarchy of metaclasses parallels the hierarchy of classes. Metaclasses are, of course, also objects and therefore instances of other, perhaps even more abstract classes. It turns out that the reality is simpler and that each metaclass is an instance of one special class called, rather predictably, **Metaclass**. Since **Metaclass** is a class, it is itself an instance of the metaclass **Metaclass** - according to the above general rule. The metaclass of **Metaclass** is, naturally, an instance of **Metaclass** like all metaclasses. Since the metaclass hierarchy parallels the corresponding class hierarchy, all metaclasses are subclasses of the metaclass of class **Object**. A few additional classes that define the shared behavior of classes complete the picture.

Classes and metaclasses are not only an elegant solution to the problem of making everything an instance of a class. The structure also has some very useful and important implications that are essential for class creation, editing, and gathering of information about classes. Programming based on the class-metaclass structure is called metaprogramming and we will give several examples of its use.

## A 4.1 Classes and Metaclasses

All Smalltalk objects are instances of classes: A Smalltalk character is an instance of **Character**, an array is an instance of **Array**, a browser is an instance of **Browser**, and so on. To be fully consistent with this principle, all classes should themselves be instances of other classes - and indeed they are. These higher level classes are called *metaclasses* and their names are identical to the names of the classes themselves. **Class Array** is thus an instance of metaclass **Array**, class **Character** is an instance of metaclass **Character**, and so on. To avoid proliferation of names and confusion, metaclasses don't have separate names and can only be accessed by sending the **class** message to the class. As an example, to access the metaclass of **Array** execute expression

### Array class

When executed with *inspect*, this opens the inspector in Figure A 4.1.

<figure><img src="image_308.png" /><figcaption>Figure A 4.1. Inspector on **Array class** - the metaclass of **Array**.</figcaption></figure>

The hierarchy of metaclasses parallels the hierarchy of classes, and when you create a new class, its metaclass is automatically created with it (Figure A 4.2).
<figure><img src="image_309.png" /><figcaption>Figure A 4.2. Class hierarchy is paralleled by metaclass hierarchy. The `.....->` relationship means 'is instance of' whereas `----->` represent subclassing.</figcaption></figure>

These principles immediately invite several questions such as - what is the class of a metaclass, how are metaclasses different from classes, how does the existence of a parallel hierarchy tree relate to the fact that the superclass of every class is class `Object`, do metaclasses have any methods and instance or class variables, and finally - what is the use of this elaborate structure.

### Main lessons learned:

* Every class is a single instance of its metaclass.

* A class and its metaclass have the same name.

* A class is accessed by its name but its metaclass is accessed by sending message `class` to the class.

* Metaclasses are not accessible through the browser but can be accessed by an inspector.

* When a class is created, its metaclass is automatically created with it.

* Metaclasses are arranged in an inheritance tree that parallels the inheritance tree of classes.

### Exercises

1. Inspect the components of the metaclass of `Character` and the metaclass of `Array`. Make preliminary comments on the variables.
### A 4.2. What is the complete class hierarchy?

If an 'ordinary' class is an instance of its metaclass, what is a metaclass? The answer is easy to find - we only need to ask each metaclass what is its class as in

Integer class class "Returns Metaclass"

Array class class "Returns Metaclass"

We conclude that all metaclasses are instances of class *Metaclass* (Figure A 4.3).

<figure><img src="image_310.png" /><figcaption>Figure A 4.3. Every metaclass is an instance of class *Metaclass*.</figcaption></figure>

But if this is so, then what is the class of *Metaclass*? Since *Metaclass* is a class just like *Array* or *Integer*, the answer, of course, is that *Metaclass* is an instance of *Metaclass* class. And what is the metaclass of *Metaclass* class? The answer is again simple - since *Metaclass* class is a metaclass and since the metaclass of every class is *Metaclass*, the metaclass of *Metaclass* class is *Metaclass* (Figure A 4.4). This is very natural when you realize that everything is governed by the following two rules:

1. The class of class X is its metaclass X class.

2. Every metaclass is an instance of class *Metaclass*.
<figure><img src="image_311.png" /><figcaption>Figure A 4.4. The metaclass of Metaclass is Metaclass class. Metaclass class is an instance of Metaclass.</figcaption></figure>

Up to this point, we have been concentrating on metaclasses and neglected the subclass relationship. As an example, we have not said what is the superclass of Object class - the head of our metaclass hierarchy. To find out, execute

### Object class superclass

The answer is that the superclass of Object class is Class (Figure A 4.5). Class Class itself is, of course a subclass of Object - like every other class. And the metaclass of Class is Class class.
<figure><img src="image_312.png" /><figcaption>Figure A 4.5. The superclass of metaclass Object class is class Class.</figcaption></figure>

However, our picture is incomplete because there are two additional classes called Behavior and ClassDescription between Class and Object. This last refinement is shown in Figure A 4.6.
<figure><img src="image_313.png" /><figcaption>Figure A 4.6. Complete hierarchy of Smalltalk classes. Object is the superclass of all classes and all metaclasses are instances of Metaclass.</figcaption></figure>

**Main lessons learned:**

* Every class is an instance of its metaclass and every metaclass is an instance of class Metaclass.

* The superclasses of Metaclass are Class, ClassDescription, Behavior, and Object, in this order.

* Object remains at the top of the class hierarchy, including metaclasses.

Exercises

1. Use the System Browser to find all superclasses of metaclass Date class.

A 4.3 What are the main properties of metaclasses?

Unlike most ‘ordinary’ classes, each metaclass has only one instance - its class. As an example, the only instance of metaclass Array class is class Array. Also, messages that we have so far classified as class messages are, in fact, instance messages of the metaclass. As an example, all class messages of class Array are instance messages of metaclass Array class., and all class messages of Object are instance messages of Object class:
Object *class* selectors asSortedCollection "Returns selectors of all *class* messages of Object."
Object selectors asSortedCollection "Returns selectors of all *instance* messages of Object."

This arrangement is logically related to the general rule of message execution:

*When a message is sent to an object, the search for its definition begins in the class of the receiver.*

As an example, when we send 13 factorial, the search for the declaration of factorial starts in class SmallInteger, the class of object A 4. It is thus quite consistent that when we send, for example, String new the search for the declaration of new starts in the class of String, in other words, in metaclass String class. And if the declaration of the message is not found there, the search continues in the superclass of String class and so on.

Besides being responsible for class methods, metaclasses inherit all their behavior from their superclasses Class, ClassDescription, Behavior, and Metaclass. All grouped in category Kernel-Classes.
We will examine the most important of these shared behaviors starting with the simplest and most general of these classes - Behavior - and then explore the functionality that its subclasses add to it. First, however, here is again the relevant part of the hierarchy:

Behavior ('superclass' 'methodDict' 'format' 'subclasses')
ClassDescription ('instanceVariables' 'organization')
Class ('name' 'classPool' 'sharedPools')
... all metaclasses ...
Metaclass ('thisClass')

and its graphical representation in Figure A 4.7.

<figure><img src="image_314.png" /><figcaption>Figure A 4.7. Metaclass-defining classes.</figcaption></figure>

**Main lessons learned:**

* Class methods of a class are instance methods of its metaclass.

Exercises

1. We have seen that class messages of a class are instance messages of its metaclass. What is the relationship of a class, its metaclass, and instance, class, and class instance variables?
## A 4.4 Class Behavior

Class Behavior defines most of the functionality shared by classes and metaclasses. It is responsible for the basic instance creation protocol, the protocol that finds the subclasses and superclasses of a class, access to methods defined in a class, and the kind of the class (more on this later). It also provides the mechanism for finding all instances of a class. Class Behavior does *not* have information that would allow a class to know about the names of its instance variables and message protocols, its class comment, and other class-related naming information; this information is the responsibility of Behavior's subclass *ClassDescription*.

To be able to implement its functionality, Behavior has instance variables *superclass*, *methodDict*, *format*, and *subclasses*. Variable *format* contains information about the storage layout of the class. *methodDict* stores associations *selector* -> *compiled method*. As an example, when you inspect `String` (a class, and thus subclass of Behavior), you will find the inherited instance variable *methodDict* among its instance variables (Figure A 4.8) and when you inspect it, you will find that its keys are selectors of all methods defined in `String`. When you inspect the value of one of these selectors, you will find that it is the compiled method of the corresponding selector - an instance of *CompiledMethod*.

<figure><img src="image_315.png" /><figcaption>Figure A 4.8. Inspectors revealing instance variable *methodDictionary* inherited from class Behavior, and its contents.</figcaption></figure>

Class Behavior does not have any class methods and its instance methods are understood by all classes. The following are examples of the most interesting Behavior responsibilities and we encourage you to browse the class for more details.

### Instance creation

The most common messages originating in class Behavior are *new* and *new*. These are the default creation messages inherited (and sometimes redefined) throughout the class hierarchy. Methods *basicNew* and *basicNew* are their duplicates that should not be redeclared in any class.

### Instances, superclasses, subclasses, and enumeration over them

Numerous behaviors are available in this category and we will illustrate a few of them on examples.
To find how many instances of Array currently exist in the environment, execute

### Array allInstances size

To find all subclasses of String execute
String subclasses "Returns #(ByteEncodeString TwoByteString Symbol GapString)."

To find which of all existing arrays has the largest size, evaluate

| size |
size := 0.

Array allInstancesDo: [:anArray| size := size max: anArray size].
size

or more simply

Array allInstances inject: 0 into: [:max :anArray| max max: anArray size]

To find all superclasses of a class, execute allSuperclasses as in

Set allSuperclasses "OrderedCollection (Collection Object)."

Instance variable format contains a code that describes what kind of class this is. The protocol
based on format makes it possible to ask a class whether it has fixed size (classes that have only named
variables) or variable size (collections represented internally as indexed elements) and, in the case of a
variable size class, whether its variables are stored as eight-bit or 16-bit quantities. As an example, all
variable size classes can be obtained by

Object withAllSubclasses select: [:aClass| aClass isVariable]

which returns

OrderedCollection (AnnotatedMethod Array BinaryStorageBytes BOSSBytes BOSSReaderMap ByteArray ByteEncodeString ByteString ByteSymbol CCompositeType CCompoundType CEnumerationType CEnvironment CompiledBlock CompiledCode CompiledMethod CProcedureType DependentsCollection Dictionary Double ExternalDictionary ExternalMethod ExternalRegistry Float FontDescriptionBundle GraphicsHandle HandleRegistry HandlerList IdentityDictionary IdentitySet ISO8859L1String LargeArray LargeInteger LargeNegativeInteger LargePositiveInteger LargeWordArray LensLinkedDictionary LensObjectRegistry LensProtectedLinkedDictionary LensRegistry LensWeakCollection LensWeakRegistry LinkedOrderedCollection LinkedWeakAssociationDictionary MacString MarkedMethod MethodDictionary MultiValueDictionary ObjectMemory ObjectRegistry OrderedCollection OS2String PoolDictionary PropertyListDictionary ScannerTable SegmentedCollection Set SignalCollection SortedCollection SortedCollectionWithPolicy SPActiveLines SPSortedLines SystemDictionary TwoByteString TwoByteSymbol UninterpretedBytes WeakArray WeakAssociationDictionary WeakDictionary WordArray)

As another example of Behavior-defined behavior, statement

(Smalltalk select: [:id| id isBehavior and: [id isBits]])

returns all elements of Smalltalk that are classes (message isBehavior) and whose instances are stored
directly as bits rather than accessed by pointers. It returns

SystemDictionary keys (#ByteString #ByteSymbol #GraphicsHandle #ISO8859L1String #Character #Double #Float #OS2String #LargeInteger #LargePositiveInteger #TwoByteString #ByteArray #BOSSBytes #WordArray #LargeNegativeInteger #UninterpretedBytes #ByteEncodeString #TwoByteSymbol #SmallInteger #BinaryStorageBytes #MacString)

Expression

Object withAllSubclasses select: [:aClass| aClass isBits]

would produce the same result. Access to instances of all other classes is by pointers.
## Functionality based on access to class hierarchy and method dictionary

Behavior provides several methods for adding new selectors to the method dictionary or removing existing ones, finding method selectors, printing hierarchies, and so on. As an example,

*   `Array printHierarchy`

returns a string containing the hierarchy of class `Array`, the same as provided by the browser. Expression

*   `Point all selectors`

returns a set containing selectors of all messages understood by instances of `Point`, in other words, names of all instance methods declared in class `Point` or its superclasses. To find all *class* messages understood by `Point`, we must ask *metaclass* `Point class` as in

*   `Point class all Selectors`

Behavior also provides access to method source code. As an example,

*   `Collection sourceCodeAt: #contains:`

returns the text of the definition of instance method `contains`:

Similarly, the following expression returns the definition of the *class* method with:

*   `Collection class sourceCodeAt: #with: 'with: anObject`

## Other protocols

Among other interesting messages, class `Behavior` provides methods for compiling source code and inserting it into the method dictionary, and a method for decompiling byte codes to produce code with artificially created temporary variables; this method is used by the Debugger when it does not have access to the source code of the selected message. All these methods use classes `Compiler` and `Decompile r` to do the actual work. The implementation is very flexible and uses a compiler and decompiler retrieved by an accessing methods so that a different compiler or decompiler may be written and used if desired.

## Main lessons learned:

*   `Behavior` is an abstract class that factors out much but not all of the behavior shared by classes and metaclasses.

*   `Behavior` introduces information about a class's superclass and subclasses, its methods, and its format. It does not provide information about instance variables, comment, and protocols.

*   The functionality of `Behavior` is inherited by all classes.
## Exercises

1. The all-important new and new: methods are defined in the instance protocol of Behavior and redefined in several other classes. However, new and new: in Behavior are instance methods whereas their use obviously is as a class methods. As an example, we use Array new: 5, sending the new: message to class Array. Moreover, the new definitions in those classes that redefine new and new: are on the class side of the protocol. This seems to violate the fact that instance methods are inherited on the instance side and class methods on the class side. Explain.

2. Write a code fragment to find all classes that implement hash or = but not both.

3. Write method find: aString to ask the user for a string and find all its occurrences in the source code of all methods declared in the receiver class. As an example, executing Object find: 'assign' should return an ordered collection with selectors of all Object instance methods whose source code contains the string 'assign'.

4. Write a code fragment to find all methods in category Collection-Streams that disable inherited methods (in other words, all methods in category Collection-Streams that use shouldNotImplement). Display the names of the methods and their classes in the Transcript.

5. Add a new <operate> command called debug to open the Debugger and start execution of the selected code. In other words, executing debug should work just like adding self halt at the beginning of the selection and executing it with do it.

6. How many class methods are unary, binary, keyword methods?

## A 4.5 Class ClassDescription

Class ClassDescription is the only immediate subclass of Behavior. It provides facilities for naming classes, method protocols, and instance variables, and for class comments. The essence of its comment is as follows:

ClassDescription adds a number of facilities to basic Behavior:

- named instance variables

- category organization for methods

- most of the mechanism for fileOut

ClassDescription is an abstract class: its facilities are intended for inheritance by the two subclasses, Class and Metaclass.

Instance Variables:

instanceVariables<Array of: String> names of instance fields

organization <ClassOrganizer> organization of message protocol

As the comment states, ClassDescription gathers all behavior shared by classes and metaclasses that is not defined in Behavior. Its definition contains many methods:

### ClassDescription allSelectors size

returns 343, meaning that 343 methods are defined in ClassDescription. We leave it to you to discover how to find that there are 12 instance method protocols. The most interesting of them are briefly described below.

## Accessing

This protocol provides access to the comment and the standard comment template via messages such as comment, comment:, and commentTemplate.
## Copying

This protocol makes it possible to copy a method, a protocol, or all protocols from one place to another. As an example,

Test copyCategory: #accessing from: Collection

copies the accessing protocol from class Collection to class Test. ClassDescription uses the term *category* to refer both to class categories and to method protocols.

## Printing

The printing protocol contains methods that return strings with instance variable names, the class definition, and so on. As an example,

Explainer instanceVariablesString

returns the string

'class selector instance context methodText '

## Instance variables

This protocol makes it possible to add new instance variables and remove existing ones, and find in which position a named instance variable is stored in the sequence representing a class's instance variables, taking into considerations inherited instance variables. This protocol is needed to understand the byte codes produced by method compilation. As an example,

Window instVarIndexFor: 'sensor'

returns 7 meaning that references to the 7th variable in messages whose receiver is an instance of Window refer to instance variable sensor.

## Organization

This protocol contains methods dealing with information about method protocols stored in instance variable organization, an instance of ClassOrganizer. As an example,

Array category

returns #'Collections-Arrayed', the name of the category containing class Array and

View organization categories

returns an array containing the names of the three protocols defined in class View:

#(#'display box accessing' #'controller accessing' #private)

Since ClassDescription has access to organization, it can also answer questions such as 'Which category (protocol) contains the method with a given selector?' As an example, the following expression returns the name of the protocol containing the class method with:

Collection class whichCategoryIncludesSelector: #with: "Returns #'instance creation'."

## File-out
This protocol supports filing out of the source code of the class.

ClassDescription has two subclasses - Class and Metaclass - which define specialized behavior of classes and metaclasses respectively. We will outline their functionality in the next section.

## Main lessons learned:

* `ClassDescription` is a subclass of `Behavior` whose most visible responsibilities include access to instance variable names, class comment, and organization of instance methods into protocols.

* The combination of `Object`, `Behavior` and `ClassDescription` defines all behaviors shared by classes and metaclasses.

## Exercises

1. When you are creating a new test version of a class, you might want to copy all protocols and methods from an existing class to the new class. Write a code fragment to do this.

2. Write a code fragment to find all unreachable methods in a class. (A method is unreachable if it is either never sent or if it is sent by a method that is itself unreachable.)

3. Write a code fragment that lists the names of instance protocols of a selected class in the Transcript. Repeat for class protocols.

4. Modify the default comment that appears in the browser for an uncommented class. The new template should automatically display a list of all instance and class variables following the current default comment.

5. Modify the default comment further to list methods that are subclass responsibility.

6. Write a short summary of the logic of the separation of class and metaclass behaviors into `Behavior` and `ClassDescription`.

7. Examples presented in this section show the importance of class `ClassOrganizer`. Write a short summary of its most important features.

8. The file-out operation is implemented in `ClassDescription`. Which class is responsible for file-in?

## A 4.6 Class Class

Class has the following comment:

Instances of class `Class` describe the representation and behavior of objects. Class adds more comprehensive programming support facilities to the basic attributes of `Behavior` and the descriptive facilities of `ClassDescription`. An example is accessing shared (pool) variables.

Instance Variables:

<table><tr><td>name</td><td>&lt;Symbol&gt; name of class for printing and global reference</td></tr><tr><td>classPool</td><td>&lt;PoolDictionary | nil&gt; of variables common to all instances (i.e., class variables)</td></tr><tr><td>sharedPools</td><td>&lt;Collection of: Dictionary&gt; access to other shared variables</td></tr></table>

Two other examples of behaviors that classes need but metaclasses don't are renaming a class (the name of the metaclass is derived from the name of the class) and subclass creation. `Class` also defines behaviors that classes share with metaclasses but implement differently. These include, for example, adding and removing instance and class variable names, and file out.

Most programmers will never use `Class` behaviors except for protocol subclass creation which contains methods for defining new classes. Even these methods are rarely used explicitly because new classes are normally defined from the browser template:

```
Paint subclass: #DevicePaint
instanceVariableNames: 'device devicePaint paintBasis'
```
classVariableNames: "
poolDictionaries: "
category: 'Graphics-Support'

Accepting the edited template simply sends message subclass: instanceVariableNames:
classVariableNames: poolDictionaries: category: inherited from Class to class Paint and creates subclass DevicePaint. Classes created with this message only have instance variables accessed by word-size pointers.
Most classes have this format and respond true to isFixed from class Behavior.
The definition of this subclass creation message is worth a look:

subclass: t instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat
"This is the standard initialization message for creating a new class as a subclass of an existing class (the receiver)."

| approved |
"Check whether arguments have proper form, such as class variables capitalized."

approved := SystemUtils
validateClassName: t
confirm: [:msg :nm | Dialog confirm: msg]
warn: [:msg | Dialog warn: msg].

approved == nil ifTrue: [^nil].
"Arguments are OK, ask classBuilder to build the class."

^self classBuilder
"First calculate all necessary parameters."
superclass: self;
environment: self environment;
className: approved;
instVarString: f;
classVarString: d;
poolString: (self computeFullPoolString: s);
category: cat;
beFixed;
"Now create new class or revise existing class."
reviseSystem

The most interesting part is the last line which creates a new class or revises the class if it already exists. Its definition is

## reviseSystem

"Mutate the system, based on whether the class already exists or not."

^self needsNewClass
ifTrue: [self createNewSubclass]
ifFalse: [self modifyExistingClass]

If the class is new, message createNewSubclass is executed. Its definition in ClassBuilder is as follows:

## createNewSubclass

"The class does not exist--create a new class-metaclass pair."

| newMeta |
self runValidationChecksForNewClass. "Check that class name is not already in use, etc." newMeta := self metaclassClass new. "Create new instance of Metaclass and initialize it." newMeta assignSuperclass: (self classOf: superclass). newMeta methodDictionary: MethodDictionary new. newMeta setInstanceFormat: (self classOf: superclass) format. class := newMeta new. "Ask the metaclass to create the class." class assignSuperclass: superclass. "Initialize instance variables of the class." class methodDictionary: MethodDictionary new. class setInstanceFormat: self computeFormat. self setStructureOf: class. classsetName: classname. self register: class inPlaceOf: nil.
self changeMicroState. "Aspects such as category and pools."

^self logNew: class "Record new class so that changes will be saved on exit."

To define a class that does not fall into the usual pattern of fixed-size class with named instance variables, edit the Browser template into one of the following forms

variableByteSubclass: instanceVariableNames: classVariableNames: poolDictionaries: category:

variableSubclass instanceVariableNames: classVariableNames: poolDictionaries: category:

edit it in the usual way, and *accept*.

If the class category given as the argument does not exist, the message creates it.

**Example: Finding which symbols in Smalltalk do not represent classes**

**Problem:** The system dictionary Smalltalk includes all global objects. They are mostly classes but also objects of other kinds. This example explores what these other objects are.

**Solution:** Since all class objects are subclasses of *Class*, we can use the following expression to extract the non-*Class* objects from the Smalltalk dictionary:

Smalltalk reject: [:value| value isKindOf: Class]

This returns the following ten or so elements out of the 1200 or so associations in Smalltalk

SystemDictionary keys (#SymbolicPaintConstants #Processor #X11InputManagerDictionary #TextConstants #Transcript #IOConstants #OpcodePool #Smalltalk #InputManagerDictionary #Undeclared #ScheduledControllers #NullInputManagerDictionary)

and includes some familiar global variables such as Transcript, Processor, and ScheduledControllers, and some pool dictionaries such as TextConstants and Undeclared. Undeclared contains all variables that the user did not declare when compiling a program and specified that they should be left undeclared when responding to the compiler query. We leave it to you to find what all these objects are.

**Main lessons learned:**

* Class inherits the behaviors of Behavior and ClassDescription and adds knowledge of class name and access to class variables and shared pools. It also provides facilities for creating new classes and controlling their format (fixed size, variable size, and others).

**Exercises**

1. Why is the name of a class defined in *Class* rather than *Behavior* or *ClassDescription*?

2. Trace the creation of a new class and write a short summary.

3. What happens when you redefine and accept an existing class?

4. What is the use of the global pool dictionary *Undeclared*?
## A 4.7 Class Metaclass

Class *Metaclass* is the equivalent of *Class* for metaclasses. It has the following comment:

Metaclasses add instance-specific behavior to various classes in the system. This typically includes messages for initializing class variables and instance creation messages particular to that class. *Metaclass* has only one instance. A metaclass shares the class variables of its instance.

Instance Variables:

```
thisClass <Class> the chief instance of the receiver, which the receiver describes
```

*Metaclass* mainly redefines behaviors which are different from *Class* behaviors. One example is *definitionMessage* which is responsible for providing the text displayed in the Browser for the definition of a class in the instance view, or its metaclass in the class view. Another example is the new message which is automatically invoked to create a metaclass during the creation of a new class. Yet another example is the *enumeration message allSubclassesDo*: which must enumerate over metaclasses, unlike its class version defined in *Behavior*.

### Main lessons learned:

* Just as *Class* defines and inherits or redefines behavior needed by classes, *Metaclass* defines, inherits, and redefines all behavior common to metaclasses.

### Exercises

1. As we know, class objects are stored in the *Smalltalk SystemDictionary*. Where are metaclasses stored?

2. We have now covered the principles of the whole class hierarchy except for its essential class - *Object*. What is the superclass of *Object* and what implications does it have?

## A 4.7 Metaprogramming - Is this magic useful?

After the first section of this chapter, you may have been wondering whether the subtle architecture of classes provides anything beyond a proof that an environment consisting only of objects can indeed be constructed. By now, it should be obvious that metaclasses and the whole structure of the class hierarchy have important practical roles. First, classes such as *Behavior* and *ClassDescription* are heavily involved in the creation of new classes and modification of existing ones. Second, these classes provide access to very valuable information about classes and their instances, and environment tools such as the Browser very much depend on them. Third, programming based on kernel classes and other classes such as compiler classes can be used to extend the programming environment (for example, by adding new browsers), the environment of a running application (for example, by adding new methods or classes at run time), or even the syntax or semantics of the Smalltalk language. This form of programming is called *metaprogramming*<fnref n="1" /> and we will now demonstrate it on several examples.

### Example 1: A creation method to create a class and its accessing methods<fnref n="2" />

The Browser's class definition template makes it possible to create a new class with variables. Most instance variables have accessing methods and these methods must be created manually. Since Smalltalk provides access to its compiler and all class information, it is possible to create tools to create accessing methods automatically.

**Problem:** Define a new class creation message that creates a class and all accessing methods for its instance variables. The usage of the method should be as in

<footnote n="1">¹ Languages that allow metaprogramming are called *reflective*. Most languages are not reflective.</footnote>

<footnote n="2">² This example is based on the classic 'blue book' by Goldberg and Robson, a Smalltalk bible that should be read by anybody seriously interested in Smalltalk.</footnote>
Object subclassWithAccessors: NewClass
instanceVariableNames: 'x y z'
classVariableNames: 'X Y Z'
poolDictionaries: 'Pool1 Pool2'
category: 'Experimental'

in other words, the same as the standard Browser template

Object subclass: NewClass
instanceVariableNames: 'x y z'
classVariableNames: 'X Y Z'
poolDictionaries: 'Pool1 Pool2'
category: 'Experimental'

except that the first keyword is different.

Solution: The algorithm is simple:

1. Create the class using the existing creation message.

2. Generate the source code of accessing methods and ask the class to format it.

3. Compile the methods. This will automatically insert them into the method dictionary.

The implementation of this algorithm (a method to be added to class Class) is relatively simple:

subclassWithAccessors: t instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat

"Create new class and its accessing methods."

| newClass |

"Compile class with its variables using existing creation message."

newClass := self subclass: t

instanceVariableNames: f

classVariableNames: d

poolDictionaries: s

category: cat.

"Formulate, format, and compile accessing methods for all instance variables."

newClass instVarNames

do: [:aName | "Enumeration over all instance variables."

| formattedText |

"Construct the text, format it, and compile it into the accessing protocol."

"First the 'get' method."

formattedText := Compiler new

format: aName, '^ ', aName

in: newClass

notifying: nil.

"Now the 'set' method."

newClass compile: formattedText classified: #accessing.

formattedText := Compiler new

format: aName, ': argument ', aName, ' := argument'

in: newClass

notifying: nil.

newClass compile: formattedText classified: #accessing]

Main lessons learned:

* A programming environment is called reflective if it provides information about its implementation and allows the programmer to modify it.

* Programming based on reflectivity is called metaprogramming.
## Exercises

1. Test that the class creation method developed in this section works.

2. Add a new command called *accessing* to the `<operate>` menu of the text view of the Browser. Its activation should open a window containing two parallel multiple selection lists containing all instance variables of the currently selected class and a *Compile* button. The left list is for creating ‘get’ methods, the right list is for creating ‘set’ methods. Selecting variable names in the two lists and clicking *Compile* creates accessing methods for all selections.

## A 4.8 Enhanced Workspace - Another example of metaprogramming

The functionality of the Workspace would be greatly enhanced if it could hold on to objects created by program fragments, in other words, if results of evaluating selected messages could persist for the duration of the existence of the workspace. Such objects could then be reused and we would not have to recreate them every time. We will show how this idea could be implemented, leaving a more complete implementation as a project.

**Problem:** Implement an enhanced workspace with an additional `<operate>` menu command *do and keep* that will execute just like *do it* but save the resulting object as a persistent part of the workspace and bind it to an automatically generated variable. An additional pop up command called *variables* will open a multiple choice menu on all variables created in this way, and allow the user to select and inspect one. Within the scope of the workspace, these variables will be treated as global.

**Solution:** We will create the Extended Workspace as a new an application, an instance of a new class called *ExtendedWorkspace*, a subclass of *ApplicationModel*. In its design, we will consider two basic scenarios: executing a code fragment to create a workspace-persistent object, and executing a code fragment containing a reference to such an object via the variable name associated with it.

### Scenario 1: Creating a workspace-persistent object

Since there is no limit on the number of objects that the user may want to add to the extended workspace, the obvious approach is to store them in a dictionary whose key is the name of the variable and whose value is the object. However, this implementation would force us to refer to the object as a value in a dictionary as in

```
worskpaceVars at: varname
```

rather than as a variable as in

```
x := y factorial
```

To be able to access the persistent objects as named variables, we can use one of at least the following two approaches: Create the new variable as a global variable (adding it to *Smalltalk*), or add it as a named instance variable to the *ExtendedWorkspace* at run time.

Using the first approach, we could automatically generate numbered variables, such as *Var0001*, *Var0002*, and so on, and delete them when the user closes the workspace. This approach is relatively simple but it does not restrict the variable to one workspace; we leave it as an exercise.

The other approach is to add a new named instance variable to the *ExtendedWorkspace* class every time when the user requests a new persistent object; this is the strategy that we will use here. This approach requires that we modify the definition of the extended workspace class at run time every time when the user adds a new workspace-persistent object. Since there may be any number of workspaces, each of them with a different number of variables, we will do this by treating *ExtendedWorkspace* as an abstract class, creating a new numbered subclass called, for example, *ConcreteExtendedWorkspace7* when we open a new workspace, and adding a new instance variable to this class whenever we add a new persistent object to this workspace. This way, different workspaces will be instances of different classes and their
'persistency' variables will be mutually unknown. The new class will be automatically deleted when the user closes the workspace.

This principle can be implemented as follows: When the user creates a new workspace-persistent object, 'mutate' the corresponding ConcreteExtendedWorkspace class by adding a new instance variable to it, and bind the object to this variable. This procedure is relatively simple as it only requires one message from Class to perform the mutation, one message to add an accessing method for the new variable, and one message to access the variable and assign the new value to it.

To test the idea of mutation, assume the existence of a test class called MutationTest, a subclass of Object, with one instance variable called var1 and its accessing message var1:. Our program will assign a value to var1 using this accessing message, add new variable var2 and its accessing method, assign a value to this variable, and inspect the result:

| x |
"Create an instance of the test class and assign a value to var1."

x := MutationTest new.

x var1: 10.

"Mutate the class by adding a new variable."

MutationTest addInstVarName: 'var2'.

"Add its accessing method."

MutationTest compile: 'var2: anObject ^var2 := anObject'
classified: 'accessing'
notifying: nil.

"Assign value to the new instance variable."

x perform: #var2: with: 20.

"x var2: 20 would not work, var: does not exist as this code fragment is being compiled."

x inspect

Everything works as we hoped: The x object has both var1 and var2 variables and their values are as expected. You can also open the browser on MutationTest to see that the new definition of MutationTest captures the changes made by this program.

The principle thus works and we can apply it to our problem. In our implementation of ExtendedWorkspace, the value assigned to the new variable will be the object that we want to make persistent and the mutation will be performed when the user executes, for example,

| x y |
x := 130 * 60 cos.

y := 130 * 60 sin.

^x @ y

with *do and keep*. This will create a new workspace-defined persistent variable and store the Point in it.

We now have the solution to the problem of creating workspace-persistent objects and their associated variables. Our next problem is how will these variables be accessed when we execute a program in the workspace.

### Scenario 2: Executing a code fragment containing a reference to a persistent object

Assume that the user created two persistent objects and assigned them to automatically created variables var1 and var2. Assume that the user now executes the following fragment in the extended workspace using, for example, *do it*.

| radius |
radius := (var1 squared) + (var2 squared)

...

To make this work as we wish, we must first understand how *do it* works. When we examine implementors of dolt, we find the following definition in class ParagraphEditor:

dolt
"Evaluate the current text selection as an expression."
self selectionStartIndex = self selectionStopIndex
ifTrue: [^self]. "If the current selection is empty, just return."
self class compilationErrorSignal
handle: [:ex | ex returnWith: nil]
do: [self evaluateSelection]

The evaluation of the selection is obviously done by `evaluateSelection` whose definition

### evaluateSelection

"Evaluate the current text selection as an expression"
| result |
result := Cursor execute showWhile:
    [self doltReceiver class evaluatorClass new
        evaluate: self selectionAsStream
        in: self doltContext
        receiver: self doltReceiver
        notifying: self
        ifFail: [self class compilationErrorSignal raise]].
self doltValue: result.
SourceFileManager default logChange: self selection string.
^result

shows that evaluation uses the stream which is the first argument of `evaluate`: `in: receiver: notifying: ifFail:.`. When you examine its receiver, you will find that `evaluatorClass` returns `SmalltalkCompiler` and the receiver thus amounts to `SmalltalkCompiler new`. Expression `self selectionAsStream` appears to refer to the highlighted text that is being evaluated. However, this text only includes the variables defined in the code fragment. Can we include our workspace-based variables as the context of evaluation of the code fragment? The definition of `evaluate`: `in: receiver: notifying: ifFail:` is as follows:

### evaluate: textOrStream in: aContext receiver: receiver notifying: aRequestor ifFail: failBlock

"Compiles the sourceStream into a parse tree, then generates code into a method. If receiver is not nil, then the text can refer to instance variables of that receiver ... etc.

and this shows that if we use our extended workspace as receiver, the evaluated code can make references to our workspace-based variables.

The next question is how to access the `dolt` method, in other words, how to get a suitable instance of a `ParagraphEditor`. Using the Browser, we find that `ParagraphEditor` is the controller (the object that handles user input) of its text editor. To obtain the controller, we must ask the text editor widget as in

#### (aBuilder componentAt: #textEditor) widget controller

However, if we just sent `dolt` to the `ParagraphEditor`, `dolt` would use its definition of `doltReceiver` which returns `nil` and this is not what we want. This means that we must define a new controller with a new definition of `doltReceiver` that returns the application model of our workspace which contains the our workspace-based variables.

We will thus define a subclass of `ParagraphEditor` containing only a new definition of `doltReceiver` that returns the application model. We will then assign this new controller to our text widget instead of the default `ParagraphEditor`. This opens two questions: How do we assign a new controller, and how do we get from the controller back to the application model.
Assigning a new controller to a widget is simple - just send `controller:` to the widget as in

#### (aBuilder componentAt: #textEditor) widget controller

To see how to get from a controller back to the application model, we will create a test application whose window contains only a text editor. In its `postBuildWith:` method, we will open an inspector on the builder:
### postBuildWith: aBuilder

aBuilder inspect

In the inspector, we can locate the controller of the widget and trace how to get back to the application model. We find that the controller has a reference to its view which is wrapped in several wrappers, the last of which is a part of a window and this window can access the builder. We can thus access the builder and its model, and this is the object that should be returned by `doltReceiver`. We leave it to you to implement the whole idea.

### Exercises

1. Implement `ExtendedWorkspace`. Don't forget to delete the class when the user closes the workspace.

2. Reimplement `ExtendedWorkspace` using global variables. Don't forget to delete the global variables when the user closes the workspace.

3. Modify `ExtendedWorkspace` so that the user can delete selected workspace-persistent variables.

4. Modify `ExtendedWorkspace` so that the user can rename workspace-persistent variables.

5. Add an inspector view for workspace variables at the bottom of the extended workspace.

## A 4.9 Another example: Wrapping objects to intercept messages

A common debugging problem is that an object is changing in some undesirable way and you don't know where. You can, of course, put a breakpoint in front of the creation message and trace your program message by message until you find where the problem occurs but this may be very time-consuming. A much better solution is to intercept all messages sent to the object in question and to open the debugger or perform some other action when such a message occurs.

If we have complete control over the object, the solution is simple - just insert `self halt` in all methods that refer to it. Very often, however, the object is a system object or there may be too many references to it. In such a case, we would like to have a tool that allows us to create this interception mechanism automatically.

One way to intercept messages to object `x` is to insert another object 'in front' of it - a 'proxy' as in Figure A 4.9. All messages to `x` then go to this proxy which can process them in an arbitrary way, for example opening the Debugger and allowing the user to pass the messages on to `x`.

<figure><img src="image_316.png" /><figcaption>Figure A 4.9. Intercepting messages to `x` by a proxy.</figcaption></figure>

A possible solution is as follows: Assume that the object in question (call it `x`) is an instance of class `X`. Modify creation messages of class `X` so that they create an instance of `X` but return an instance `p` of `Proxy` that knows about `x`. All communication with the returned object will now go to `p`, and `p` can direct it to `x` and perform any other operations specified by the programmer.

Having formulated the principle, let's consider how we can implement it. The obvious way is to define `Proxy` so that it understands all messages understood by `x` (defined in `X` and all its superclasses). These messages would have to be modified to allow the programmer to execute the programmer-specified action and then pass the message on to `x`. Although this approach can be automated, it is very unattractive because it requires defining possibly hundreds of messages in `Proxy`.

An interesting alternative to making sure that `p` *understands all messages of x* is to make sure that `p` *understands as few messages of x as possible*. When a messages understood by `x` is then sent to `p`, `p` does not understand it, this sends `doesNotUnderstand: aMessage` to `p`, and if we redefine `doesNotUnderstand: in
Proxy to insert a programmer action and pass the original message to x, the problem is solved (Figure A 4.10). This approach is very simple and we will now implement it.

<figure><img src="image_317.png" /><figcaption>Figure A 4.10. Intercepting messages to x by a proxy via `doesNotUnderstand:.`</figcaption></figure>

The essential question in defining Proxy is what should be its superclass. Since we want it to share as few method with class X as possible, we must place it as high in the hierarchy as possible so that it inherits as few messages as possible. This seems to suggest that Proxy should be a subclass of Object. But if it is, it will still understand all Object's messages and these quite likely include messages that we would like to intercept. As an example, if X is an Array, we may want to intercept `at:put:` - but this message is defined in Object. We thus want to eliminate even inheritance from Object. But if we don't want even Object to be the superclass of Proxy, then what should the superclass be? The obvious question is *nothing* – the proxy should not have a superclass – just like Object which also does not have a superclass. In other words, in place of a superclass, use `nil`. And this exactly what we will do.

Having decided this, the next question is what behaviors should Proxy implement and what attributes it needs. Instances of Proxy must obviously have access to the instance of the original addressee of X messages; we will call its instance variable `addressee`. The only behavior that appears necessary is a new definition of `doesNotUnderstand:` that allows the programmer to specify a block to be executed before the intercepted message is passed to `addressee`. To understand the possible implications, let's examine the existing definition of `doesNotUnderstand:` in class `Object`:

**doesNotUnderstand: aMessage**

"The default behavior is to create a Notifier containing the appropriate message and to allow the user to open a Debugger. Subclasses can override this message in order to modify this behavior."

| selectorString |
|---|
| `selectorString :=` |
|   | Object errorSignal |
|   |   handle: [:ex | ex returnWith: '** unprintable selector **]` |
|   |   do: [aMessage selector printString]. |
|   | Object messageNotUnderstoodSignal |
|   |   raiseRequestWith: aMessage |
|   |   errorString: 'Message not understood: ', selectorString. |
|   | ^self perform: aMessage selector withArguments: aMessage arguments |

The argument is an instance of class `Message` with information about the selector of the intercepted message and its argument. `doesNotUnderstand:` first attempts to convert the selector to a string and raises an exception (Chapter 11) if it fails. It then opens the usual exception window, and if the user selects *proceed*, it attempts to execute the original message. This normally fails but in our case, we can take advantage of this behavior to pass the message to `addressee` or execute another action.

We must now decide what should happen when `p` intercepts a message to `x`. We may or may not want to open the exception window (we might, for example, only want to collect some statistics about messages to `x` without ever opening the Debugger). To make this possible, we will create `p` with a Boolean specifying whether to open the exception window or not.

The next thing we want is to be able to execute an arbitrary block because we don't know what the user might want to do with the intercepted message. What should this block be allowed to do? We cannot know, but in principle it should be able to do anything with the information now available which includes: `addressee`, `selector`, and `arguments`. We will thus assume that the block is a three-argument block with these three objects as its arguments, to provide the maximum possible flexibility. The design is now complete and we are ready to implement `Proxy`. Its definition is
nil subclass: #Proxy

instanceVariableNames: 'addressee doesNotUnderstandBlock openNotify'

classVariableNames: ""

poolDictionaries: ""

category: 'tests - proxy'

Instance variable doesNotUnderstandBlock is the three-argument block to be executed when a message is intercepted, and openNotify is a Boolean that determines whether the intercepted message should open an exception window or not. Accepting this definition in the Browser will open a confirmation window because nil should not normally be the superclass; click OK and proceed.

The creation message for Proxy must create a new Proxy object with an addressee, a block, and information about whether to open an exception window or not:

### newOn: anObject block: aBlock openNotify: aBoolean

^ (self new) addressee: anObject; block: aBlock; openNotify: aBoolean

Finally the doesNotUnderstand: method. In VisualWorks, compilation of a subclass of nil automatically adds a few essential methods and these include the standard doesNotUnderstand: . We change it according to our earlier analysis as follows:

### doesNotUnderstand: aMessage

"Provide the default behavior but add control over the exception window, execution of a programmer supplied block, and finally execution by addressee."

(Object canUnderstand: aMessage selector)

ifTrue:

[self class copy: aMessage selector from: Object.

^self perform: aMessage selector withArguments: aMessage arguments].

openNotify ifTrue: [Object messageNotUnderstoodSignal raiseRequestWith: aMessage errorString: 'Message not understood: ', aMessage selector].

doesNotUnderstandBlock

value: aMessage

value: aMessage arguments

value: addressee.

^addressee perform: aMessage selector withArguments: aMessage arguments

This completes the definition of Proxy and we are now ready to test it. To do this, we will define a new class called TestProxy with a single instance variable called var and a single instance method

### var: anObject

var := anObject

Assume that we don't want to open an exception window with each message to a TestOfProxy, and that we want it to print which object is being addressed, what is the selector of the intercepted message, and what are its arguments. For the purpose of this test, we will thus write a new TestOfProxy creation method defined as follows:

### newWithProxy

"Create a proxy that does not open exception window and prints information about myself and the intercepted message."

| newInstance |

newInstance := self new.

^Proxy newOn: newInstance

block: [:message :arguments :addressee | Transcript cr; show: addressee printString, 'gets message ', message selector, 'with arguments: ', arguments printString]

openNotify: false

To test our scheme, execute
TestOfProxy newWithProxy var: 13; var: 15

and you will get the expected result. When you are finished testing, remove this method so that TestProxy
again behaves ‘normally’.

Main lessons learned:

* It is possible to define classes outside the Object hierarchy. In fact, one can create another completely separate hierarchy by using nil as the 'superclass' of the root of this hierarchy.
## Exercises

1. Write a program to run two series of tests of Array methods using Proxy. In the first series, print a log of message sends by your program in the Transcript. In the second series, let each intercepted message open an exception window.

2. The idea of parallel class hierarchies rooted in nil is used in the complete VisualWorks library. Find all classes in the library whose superclass is nil.

3. Use Proxy to display a confirmer with the name of the intercepted message (Figure A 4.11). An exception window opens only if the user clicks yes.

4. Proxy will be even more powerful if the programmer can specify an additional object to be used in the block. This object could, for example, collect some statistics. Extend the definition of Proxy accordingly.

5. Automate the proxy creation mechanism as much as possible.

6. Write a method that will insert a breakpoint into every method in a given class that contains a reference to a given instance variable. Write also a method that will remove all these breakpoints.

<figure><img src="image_318.png" /><figcaption>Figure A 4.11. Confirmer for Exercise 3.</figcaption></figure>

## Conclusion

Every class in Smalltalk is the single instance of a matching metaclass which is automatically created when the class is first compiled. Metaclasses use the same names as their corresponding classes and cannot be accessed through the System Browser in the same way as 'regular' classes. Instead, the class message must be addressed to the corresponding class.

Metaclasses form a hierarchy that parallels the hierarchy of classes, with the metaclass of Object at the top. Metaclass Object, however, has itself several superclasses that define behavior shared by all classes and all metaclasses, and their top superclass is class Object. Class Object thus remains a superclass of all classes, including metaclasses.

Like all classes in Smalltalk, each metaclass is itself an instance of a class. Each metaclass is an instance of class Metaclass.

Whereas class Metaclass defines behaviors particular to metaclasses, behaviors particular to classes are defined in class Class. Much of the behavior of Metaclass and Class is shared and defined in class ClassDescription which is a subclass of Behavior, itself a subclass of Object. As the names suggest, Behavior defines functionality related to basic class behaviors such as methods for creating new classes. ClassDescription adds information about details of class descriptions such as comments and variables. Class, Metaclass, Behavior, and ClassDescription are grouped together in category Kernel Classes.

Although the basic class hierarchy has Object as its root, it is possible to create additional parallel hierarchies rooted in new classes whose superclass is undefined - nil.

On the theoretical and esthetic side, the hierarchy of metaclasses and kernel classes gives a constructive proof that a system can be designed consisting of objects and nothing else. On the practical side, these classes provide many essential behaviors that make possible Smalltalk programming tools such as the Browser, allow creation of classes and access to their descriptions, and provide a very powerful mechanism that makes it possible to reshape the Smalltalk environment from within, even at run-time. This property is called reflectivity and programming based on reflectivity is called metaprogramming. Reflectivity and metaprogramming make Smalltalk one of the most powerful programming environments.
**Important classes introduced in this chapter**

Classes whose names are **boldfaced** are very important, classes whose names are printed in *italics* are less important, classes whose names are printed in regular font are not of much interest.

*Behavior, Class, ClassDescription, ClassOrganizer, Metaclass.*

**Terms introduced in this chapter**

*metaclass* - the class of a class; accessed by sending *class* to class name

*kernel class* - a class providing access to shared class behavior and system organization

*metaprogramming* - programming based on kernel classes

*reflectivity* - features of a programming language allowing the programmer to modify the language and its programming environment programmatically
# Appendix 5 - Style recommendations

## Overview

This appendix contains a small selection of Smalltalk conventions, idioms, and patterns. The stylistic part contains a few simple and natural guidelines for naming variables and methods, writing comments, naming method protocols, and similar topics. The idioms and patterns part gives examples of some of the techniques used by experienced Smalltalk programmers.

In some details, stylistic guidelines and preferred patterns vary from one programmer to another and some of our suggestions thus differ from those recommended by some other authors. In the end, it is not important whether you follow our recommendations or somebody else's because what matters is to have a stable style rather than follow one particular style.

## A 5.1 Introduction to Smalltalk style guidelines

Having a set of rules for writing Smalltalk programs makes programs easier to read and understand and this is very important for readability and understandability. If you are a part of a team or a student in a course, setting a common set of stylistic guidelines is essential. Most of the following guidelines have been extracted from a much larger set listed and justified in [Skublics, et al.] and [Beck]. We recommend these two highly respected books as additional reading.

## A 5.2 Naming

**Guideline N.1: Uppercase and lowercase first letter.**

Start names of shared objects with upper case letter (classes, global variables, class variables, pools), start names of methods, keywords, parameters, and local names (instance, temporary, and block variables) with lower case.

Examples: Shared objects - Number, Smalltalk, Pi, TextConstants; methods and local objects - factorial, between:and:, width.

**Guideline N.2: Multiword names.**

When a name combines several words, start each word with a capital letter.

Examples: SmallInteger, studentNumber.

**Guideline N.3: Choice of name.**

Use short descriptive names and avoid abbreviations except where standard.

Examples: Number, today, factorial, between:and:, BTree (balanced tree)

**Guideline N.4: Names of methods.**

Method names should suggest the kind of object being returned.

Examples: isHungry, name, between:and:

**Guideline N.5: Names of keywords.**

Use names describing the role of parameters.

Examples: between:and:, name:address:

**Guideline N.6: Variable names versus argument names.**

Variable names should indicate the role of the variable, argument names should indicate the kind of argument expected.

Examples: Variable names - width, seed; argument names - name: aString, + aNumber
**Guideline N.7: Argument names when type is repeated.**

When several arguments are of the same type, distinguish them by indicating their role.

Example: origin: originPoint corner: cornerPoint

**Guideline N.8: Names of block arguments.**

Name block arguments according to their role.

Example: employees do: [:employee| ...]

**Guideline N.9: Names of accessing methods.**

Name accessing methods by names of accessed variables.

Examples: Use width, width: to get or set variable width.

**Guideline N.10: Names of state-related test methods.**

Use a state-related phrase for tests and access of Boolean variables.

Examples: empty, hasBorder, isOn

**Guideline N.11: Names of action methods.**

For methods that perform an action, use imperative form of verbs describing effect.

Examples: display:, enable, turnOn, turnOff

**Guideline N.12: Names of widget properties.**

Use widget label to name *Action*, *Selection*, and *Aspect* properties.

Examples: Use action method save for action button named Save, use selection property red for check box named Red, use aspect named name for input field with label Name.

## Exercise

1. Browse the class library and find ten well selected names and five poorly selected names.

## A 5.3 Comments

**Guideline C.1:** Use meaningful, short, and grammatically correct comments using correct spelling, full sentences, and standard English punctuation. Use active voice.

Example: "Create and return a Point at the given radius and angle."

**Guideline C.2:** Follow the Browser method template: Start all methods except accessing and very short self-explanatory methods with a comment explaining some or all of the following: the purpose of the method, its principle, its prerequisites, its effect, its use, the role of its arguments, the returned object.

Example: "Include all elements of aCollection as the receiver's elements. Answer aCollection."

**Guideline C.3:** Minimize the number of comments in method body - code should be self-explanatory.

**Guideline C.4:** For class comment, use the template displayed in the browser for class comment. Use active voice. If you wish to use first person, use it consistently.

Example: See comment of class Array, Float, Date for examples.

## Exercise

1. Browse the class library and find five good and bad method and class comments.
## A 5.4 Formatting

**Guideline F.1:** Use automatic formatting. Since the VisualWorks formatter exhibits some undesirable behavior, such as misplacing comments, we recommend using the formatter written by Randy Giffen and included in our software package. If your formatter allows several formatting styles, use one consistently.

### Exercise

1. Write a method without any regard for formatting and format it. Compare the readability of the two versions.

## A 5.5 Names of common protocols

Wherever appropriate, use the following protocol names common in the class library:

### Class protocols

* class initialization
* examples
* instance creation
* interface spec
* resources

### Instance protocols

* accessing
* adding
* arithmetic
* converting
* comparing
* controller accessing
* copying
* events
* displaying
* enumerating
* menu commands
* printing
* private
* private - menu messages
* removing
* testing
* updating

### Exercises

1. Browse the class library and find the proportion of the above names among protocol names.

2. Browse the class library and find ten non-standard protocol names.

## A 5.6 Introduction to idioms and patterns

Over the more than 20 years of Smalltalk existence, Smalltalk programmers invented and tested various ideas and evolved a body of rules that help writing readable, easily extendible, and efficient code. Why not take advantage of this body of knowledge and save yourself months of frustrating trial and error?

Most of the following guidelines have been borrowed from [Beck] and [Skublics, et al.]. Our list is limited to idioms and patterns used in this book and we recommend highly that you read the recommended references for more details and many more guidelines.
Some of the following guidelines can be classified as patterns, meaning that their validity extends beyond Smalltalk. Other guidelines can be classified as idioms because they are specific to Smalltalk and don't apply to other languages.

## A 5.7 General patterns

### Pattern G.1: Don't Say Anything Twice

When the same piece of code appears in several places in one class, convert it to a method. When the same object is calculated more than once in one method, cache it in an instance variable. When the same object is needed in several methods in the same class, create an instance variable to hold it.

### Pattern G.2: Lots of Little Pieces

Shorter methods, and objects with fewer components are better. They are easier to understand and more reusable. Like all smaller things, they don't 'break' so easily to become useless.

### Pattern G.3: Think of Alternatives

When designing a system or a class think of extensions and modifications. Can they be done by adding a few new classes or will some classes have to be rewritten?

### Pattern G.4: Think of Specialization

If you anticipate subclassing, separate code into methods that will be inherited in their entirety from methods that will be redefined in subclasses.

## A 5.8 Methods

### Idiom M.1: Short Method

Keep methods to a few lines. Most methods should fit into the Browser window.

### Idiom M.2: Self-Contained Method

A method should perform one identifiable task.

### Idiom M.3: Composed Method

When a method gets too long, divide it into self-contained methods, all at the same level of abstraction.

### Idiom M.4: Constructor Method

Creation methods should create ready-to-use objects. When appropriate, provide methods that create instances with initialized instance variables.

Example: Rectangle class >> origin: originPoint corner: cornerPoint rather than just Rectangle new.

### Idiom M.5: Debugging Method

To support debugging, write a printOn: method early in the coding stage of a new class.

### Idiom M.6: Display Method

To support display of selected aspects of an object in a widget such as a list, write a displayString method.

### Idiom M.7: Selection Avoiding Method - Polymorphism

To avoid complicating code with multiple ifTrue:ifFalse: messages, use polymorphism - define the same selector with different implementations in all classes whose instances may be accessed in the same way.

Example: Geometric objects define methods displayStrokedOn: and displayFilledOn: and may thus be used interchangeably in code including enumeration. This avoids the need for testing what kind of geometric objects is being displayed, speeding up operation, making code more readable and more easily extendible.

### Idiom M.8: Double Dispatch Method
To avoid complicating code with multiple `ifTrue:ifFalse:` messages when the combination of the receiver and the argument determine the operation, send a message to the argument.

Example: Implementation of `+` `aNumber` uses `aNumber sumFromInteger:` self in `SmallInteger`, `aNumber sumFromFloat:` self in class `Float`, and `aNumber sumFromFraction:` self in class `Fraction`

**Idiom M.9: Simple Delegation**

When an object needs work involving one of its components, delegate the message to the component.

Example: The `printOn:` method in `Point` sends `printOn:` to the `x` and `y` components. Note: A stricter definition of delegation classifies this principle as forwarding.

**Idiom M.10: Self Delegation**

When the delegate needs to know about the delegating object, send message with a `for:` keyword and `self` as the argument.

Example: A dialog window may need access to the instance variables of the application model that created it. If the dialog's model is different from the application model, open the modal dialog with `openFor:` self from the main application, thus providing access to the main application's state.

## A 5.9 Behaviors

**Idiom B.1: Instance Variable Enumerator**

To enumerate over selected instance variables, create accessing methods for each variable, and use an array of symbols representing the variables' accessing methods and enumerate using `perform:`.

Example: Assume that we have variables and accessing methods called `part1`, `part2`, `part3`, `part4`, `part5`. To calculate the total of part values, use `#(#part1 #part2 #part3 #part4 #part5) inject: 0 into: [:part :total] (total + self perform: part) value]`

**Idiom B.2: Pluggable Behavior**

When the method to be executed is not known beforehand, for example when the desired method depends on context, use one of the forms of `perform:` with a symbol representing the method.

Examples: Operation of widgets is based on using their aspect accessing method via `perform:` because the method needed to execute the method is not known until the user defines it as the widget's property. Similarly, execution of pop up menu commands is based on `perform:`.

**Idiom V.3: Redefining Equality**

If a new class cannot reuse the inherited equality, redefine `=` and `hash`. Both should use equality and hash of those instance variables that are relevant for comparison. The `hash` method frequently uses `xor:` or `+` on the components used for `=`. Remember that *two objects that are equal must have the same hash value* (but not necessarily the other way around).

Examples: Equality in class `ColorValue` is defined as

`= aColor`

`^aColor class == self class and:`

`[aColor scaledRed = red and:`

`[aColor scaledGreen = green and:`

`[aColor scaledBlue = blue]]]`

and because it uses colors, `hash` is redefined as

`hash`

`^red hash + green hash + blue hash`

Class `Rectangle` redefines `=` in terms of equality of corners and origins, and `hash` is thus defined as

`hash`

`^origin hash bitXor: corner hash`

**Idiom B.4: Inclusion Test Reversal**

Testing whether an object has one of several possible values can often be performed more easily by testing whether the collection of all possible values includes the object.

Examples: The first impulse for testing whether a `Character` is a vowel is
**isVowel**

| lowercase |

lowercase := self asLowercase.

^lowercase = $a | lowercase = $e | lowercase = $i | lowercase = $o | lowercase = $u

but a better solution is

**isVowel**

^#($a $e $i $o $u) includes: self asLowercase

or

**isVowel**

^'aeiou' includes: self asLowercase

## A 5.10 Variables

**Idiom V.1: Explicit Default Initialization**

To initialize selected variables to default values, create a new method including initialize.

Example: If variable accounts is an OrderedCollection, include

accounts := OrderedCollection new

or a similar statement in the initialization method.

**Idiom V.2: Lazy Initialization**

If the value of a variable is not immediately required or may never be required, don't initialize it when the object is created. Instead, define a getter method that returns the value of the variable if the variable is not nil and assigns and returns the default value if the variable is nil.

Example: Accessing methods for widget aspects created with *Define* use lazy initialization.

**Idiom V.3: Default Value Method**

To make initialization more flexible, create a default method that calculates and returns the default value.

Examples: Abstract class Filename uses message defaultClass to determine which of its concrete subclasses will handle messages addressed to Filename objects. Class String uses the same principle. Changing the default then requires changing only the getter method.

**Idiom V.4: Constant Method**

To provide access to significant class values or to values shared across all instances, create a class variable or a class method that returns the value.

Examples: Class Float has method Pi that returns the value of π. Class ColorValue has class variables representing the most frequently used color values and class methods that return them.

**Idiom V.5: Direct Variable Access**

For better readability, access variables directly. Advantages: faster and protects encapsulation.

Examples: name := aString instead of self name: aString and width printString instead of self width printString.

**Idiom V.6: Indirect Variable Access**

For greater flexibility, access variables by accessing methods. Advantages: Provides a central place where change of variable occurs (easier to monitor), makes it easier to change internal class implementation.

Disadvantage: Breaks encapsulation (other objects can access variables), negligible message send overhead.

Example: Lazy initialization (Idiom V.2) requires that the variable be always accessed by an accessing method.

Note: The opinion on the use of *Direct* versus *Indirect* access varies from one expert to another.

**Idiom V.7: Safe Collection Access**

When an object contains a collection, access its elements via enumeration rather than by accessing the collection directly.
Example: Assume that class Account contains variable transactions. Method transactionsDo: aBlock allows flexible access to all transactions without allowing the accessor to change the value of individual transactions which is what would happen if you provided accessor method transactions.

**Idiom V.8: Caching Temporary Variable**

Use temporary variable to preserve a calculated object used repeatedly in a method or a block. If the calculation is lengthy or repeated many times, this will improve execution speed.

Example: Replace

department employeesDo:

[:employee| Transcript show: 'Department', department name, 'Employee',
employee name; cr]

with

| label |

label := 'Department, department name, 'Employee'.

department employeesDo: [:employee| Transcript show: label, employee name; cr]

**Idiom V.9: Explaining Temporary Variable**

When a calculation requires a complex expression, save its parts in well-named temporary variables to make the code more readable.

Example: Replace

tax := ((incomes inject: 0 into: [:income :sum| sum + income]) -
          (expenditures inject: 0 into: [:expenditure :sum| sum + expenditure]) -
          (donations max: (donations - minDonations) * donationsRate)) * taxRate

with

| totalIncome totalExpenditures deductibleDonations |

totalIncome := incomes inject: 0 into: [:income :sum| sum + income].

totalExpenditures := expenditures inject: 0 into: [:expenditure :sum| sum + expenditure].

deductibleDonations := donations max: (donations - minDonations) * donationsRate.

tax := (totalIncome - totalExpenditures - deductibleDonations) * taxRate

**Idiom V.10: Object Sharing Instance Variable**

When several methods in the same class need the same object, save it in an instance variable instead of passing it as method argument.

**Idiom V.11: Concatenating Stream**

When concatenating several collections (usually String objects) use a WriteStream and its contents method.

Example: The printString: method defined in Object creates a WriteStream, passes it as an argument to printOn:, and returns the contents.

**Idiom V.12: Cascading**

When sending a series of messages to the same receiver, use cascading. Emphasize the receiver by indentation to improve readability.

Example:

self builder componentAt: #save

lookPreferences准色: color;

enable;

beVisible
**Idiom V.13: Adding, removing, and yourself**

Adding and removing methods in collection and stream classes return the object being added or removed rather than the modified receiver. Use message **yourself** to return the modified receiver.

Example: `newCollection := oldCollection add: 13; yourself`
# Appendix 6 - Projects

## Overview

This appendix contains descriptions of many Smalltalk projects. Some are very detailed, others are just ideas that require some creative thought to arrive at a detailed specification. Some of the projects are easy, others are difficult.

**A.6.1 1.** When delivering a VisualWorks product to a customer, you might want to make it very difficult for the client to make sense out of your code - for competitive reasons. One strategy that has been suggested is to change the names of all your classes and methods to some meaningless sequences of characters. Develop a new class called Srambler which will do some or all of the following with each of the user-specified classes: Delete all comments (class and methods), rename the class and all its categories and methods to some random characters of strings. Note that the names must be changed wherever they are used, at all places in the library. Implementing this problem in a fully automated way is impossible because of polymorphism. You will thus have to implement the class so that the user provides some interactive help in the scrambling process.

## 2. 4.5 Dental Office

### 4.5.1. System Description

We are to implement a simple implementation of software required by a small dental office. The program will keep records on individual patients including their bills, the schedule of patient appointments, information on staff including their schedules and paychecks, and keep track of dental material and potential suppliers. In more detail, the information to be kept includes the following:

* Patient record

* Name (first, middle, initial)

* Address (-mailbox, street, city, and postal code)

* Phone number

* List of appointments (date, time, task, bill, payment received)

* Dental record (tooth-by-tooth: filled, extracted, nothing)

* Amount currently due

* Notes

* Staff record

* Name (first, middle, initial)

* Address (-mailbox, street, city, and postal code)

* Phone number

* List of shifts (dates)

* Hourly wage

* Material

* Item name

* List of suppliers

* Supplier

* Name of company

* Address

* Phone

* List of materials supplied with prices
We want to be able to perform the following tasks:

* Patient record

* Add

* Delete

* Display

* Edit

* Print

* Create appointment

* Cancel appointment

* Change appointment

* Print information about appointment

* Staff

* Add

* Delete

* Display

* Edit

* Print

* Schedule (assign, change, cancel)

* View shifts for current month

* Print paycheck

* Material

* Add

* Delete

* Display

* Edit

* Print

* View all potential suppliers

* Create order

* Print order

* Supplier

* Add

* Delete

* Display

* Edit

* Print

The Context Diagram is as in Figure 4.8.

<figure><img src="image_319.png" /></figure>
<caption>Figure 4.8. Context Diagram of Dental Office.</caption>

Our next task is to find the scenario. Because this system is much more complicated than the library catalog, there will be many scenarios and we will thus restrict ourselves to a few examples only.

### Scenario 1: Adding a new patient

The operator (secretary or dentist) selects the *New patient* task from the main window of the user interface, the system opens a window with fields for all required patient information, the operator enters all required information and clicks *Accept*, the system stores the new patient record.

### Scenario 2: Making an appointment

The operator selects the patient from the list and the *Open patient record* task in the main window, the system opens a window with the patient record, the operator selects the *Appointment* task, the system opens an appointment window, the operator fills in the information, clicks *Accept* in the appointment window which closes, clicks *Accept* in the Patient record window which closes, the system stores the information.

### Scenario 3: Creating and printing a material purchase order

The operator selects the *Create purchase order* task in the main window, the system opens a window with a list of materials, the operator selects a material, the system displays a list of suppliers of the selected material, the operator selects one, completes the *Quantity* field, clicks *Accept and Print*, the system saves the order and prints it.

This time, we will only show the main user interface window and leave it to you to decide which other windows are required and to design them. The main window is shown in Figure 4.9.

<figure><img src="image_320.png" /><figcaption>Figure 4.9. Main window of Dental Office.</figcaption></figure>
3.

4.3 Computerized Library Catalog

4.3.1 System Description

We are to develop a computerized catalog for keeping track of books and borrowers. The program
will allow authorized personnel (referred to as librarians) to perform the following tasks:

* Book

* Add a new book to the catalog

* Modify an existing book

* Delete a book

* Sign a book out to a borrower

* Sign a returned book in

* Search for a book in the catalog

* Borrower

* Add a new borrower

* Edit information about an existing borrower

* Delete a borrower

* Search for a borrower

The information held about books and records is as follows:

* Book

* One or more authors identified by first, middle, and last names

* Title

* Publisher name

* Year of publication

* In or out of library

* Borrower

* First name, middle name, and last name

* Address consisting of street name and number, city, telephone number

* List of borrowed books with dates when the books were borrowed

The specification assumes the user interfaces shown in Figures 4.5, 4.6, and 4.7.
<figure><img src="image_321.png" /><figcaption>Figure 4.5. Main window of library catalog.</figcaption></figure>
<figure><img src="image_322.png" /><figcaption>Figure 4.6. Book information window.</figcaption></figure>

<figure><img src="image_323.png" /><figcaption>Figure 4.7. Borrower information window.</figcaption></figure>

The following are some of the main usage scenarios:
**Scenario 1:** Librarian opens the application.

**High level conversation:**

1. User types a Smalltalk expression and executes it.

2. System opens a password window

3. User types password.

4. If the correct password is entered, System opens user interface shown in Figure 4.1; a notifier window opens otherwise.

**Scenario 2:** Librarian adds a new book.

**High level conversation:**

1. User clicks New book in the main window.

2. System opens a form window providing text fields for all required information. We will call this window the book form.

3. User enters at least author name and book title and indicates end of task by clicking Accept in the form window.

4. System closes form window and updates book catalog.

**Scenario 3:** Librarian modifies an existing book record..

**High level conversation:**

1. User selects the desired book in the catalog and clicks Open.

2. System opens a book form with current information about the book.

3. User edits the form and indicates end of task by clicking Accept in.

4. System closes form window and updates book catalog.

**Scenario 4:** Librarian deletes a book.

**High level conversation:**

1. User selects the desired book in the catalog and clicks Delete.

2. System opens window requesting confirmation that the book is to be deleted.

3. System closes confirmation window and updates book catalog if the user confirmed.

**Scenario 5:** Librarian signs a book out to a borrower.

1. User selects the desired book in the catalog.

2. User selects a borrower.

3. User clicks Borrow book.

4. System updates book and borrower catalogs.

**Scenario 6:** Librarian signs a book in.

**High level conversation:**

1. User selects a book.

2. User selects a borrower.

3. User clicks Return book.

4. System updates book and borrower information.

**Scenario 7:** Librarian adds a new borrower.

**High level conversation:**

1. User clicks New borrower in the main window.

2. System opens a form window providing text fields for all required information. We will call this window the borrower form.

3. User enters at least borrower name and address and indicates end of task by clicking Accept in the form window.

4. System closes form window and updates borrower catalog.

**Scenario 8:** Librarian modifies an existing borrower record.
High level conversation:

1. User selects borrower in the catalog and clicks Open.

2. System opens a book form with current information about the book.

3. User edits the form and indicates end of task by clicking Accept in.

4. System closes form window and updates borrower catalog.

Scenario 9: Librarian deletes a borrower.

High level conversation:

1. User selects borrower and clicks Delete.

2. System opens window requesting confirmation that the borrower is to be deleted.

3. System closes confirmation window and updates borrower catalog if the user confirmed.

Scenario 10: Librarian requests help information.

High level conversation:

* User clicks Help.

* System opens help window.

* User clicks Close in the help window.

* System closes help window.

This scenario is so obvious that it is questionable whether it should be included. We will not include such trivial scenaria in the future.

A variety of other important scenaria exist and we leave them as exercises.

The specification and scenaria that we just read contain several new terms and it will be useful to create a dictionary with their exact definitions. *We will add a Term Dictionary as a new deliverable for Specification of Requirements.* The dictionary for our problem is as follows:

* Book form - dialog window in Figure 4.6. Contains book information and additional control buttons.

* Borrower form - dialog window in Figure 4.7. Contains borrower information and additional control buttons.

(A dialog window is a window that must be completed and closed before another window can be accessed.)

Context Diagram

The last task is to draw a diagram showing the main components and deciding which of them are a part of the application, and which external actors. From the description, we conclude that there is a single external actor - the librarian - and that the system to be developed consists of a user interface, an application model, a catalog of books, and a catalog of borrowers.

<figure><img src="image_324.png" /><figcaption>Figure 4.4. Context Diagram showing readily identifiable parts of Library Catalog and external actors.</figcaption></figure>

This completes System Description and we proceed to Preliminary design.

4.3.2 Preliminary design
The steps in Preliminary Design are

1. Identify candidate classes and create CRC cards with their brief descriptions.

2. Identify responsibilities of candidate classes and record them on their CRC cards.

3. For each class, identify collaborator classes required to fulfill this class's behaviors and record them on the CRC card.

4. Verify completeness of CRC cards by walkthroughs, checking that the identified classes and their behaviors can implement all scenarios obtained during the System Description step.

### Identify candidate classes and their responsibilities

This is the most difficult part of the whole procedure and the commonly proposed guideline for finding the classes is to read the description carefully, looking for nouns as possible class candidates. In our relatively simple example, the obvious candidates are the windows and the other components of the user interface, the list of books, and the list of borrowers.

One would expect that *windows and their components* are already in the Smalltalk library and this is indeed the case. We can thus eliminate them from our consideration since we are only interested in the *new* classes that we will have to create.

The list of books and the list of borrowers are both lists, collections of objects. Collections of objects appear in almost every application and we would again expect that suitable collection classes are already in the Smalltalk library. This is indeed so and we thus don't have to include them in our design.

The only remaining objects therefore are books and borrowers. A book object is basically an information object and its intelligence is limited to knowing certain information, being able to provide it when requested (for example when a window needs to display it), and being able to change it when requested (when the librarian enters new information). A borrower object is another information object capable of holding and accessing information; only the type of information it holds is different. A reasonable conclusion is that we need to declare two new classes - *Book* and *Borrower*. This, however, probably is not the best solution for two reasons: The first is that both of these objects contain a bit too much information, the second is that the information held by both *Book* and *Borrower* contains smaller and logically self-contained concepts - person information and address information - and that some of this information - namely person information - is, in fact, shared by both. We conclude that a more elegant solution is to define the following classes:

**Address:** Contains and can access information about street name and number and city.

**Book:** Contains and can access information about book consisting of author, title, publisher, and isIn information.

**Borrower:** Contains and can access information about borrower consisting of borrower, address, telephone number, and list of borrowed books.

**Person:** Contains and can access the first, middle, and last name of a person.

Besides greater simplicity of these classes, the advantage of this approach is that we may be able to reuse them in another application. After all, persons and addresses are very common. We summarize our decisions on CRC cards as in

**Book:** I hold information about a book in the library - its author, title, publisher, year of publication, and status (in or out).

**Responsibilities**

**Collaborators**

* Get/return author information

* Person

* Get/return title information

* Get/return publisher information

* Get/return year information

* Get/return isIn information
We leave it to you to complete CRC cards for the remaining classes as an exercise.

Verify completeness of class list by scenaria walk throughs

Scenario 1: Librarian opens the application.

The librarian types a Smalltalk expression and executes it. The application open the user interface

Scenario 2: Librarian adds a new book to the catalog.

Librarian selects the *New* task from the main window, a window appears providing text fields for all required information. The librarian enters at least author name and book title, indicates end of task by clicking *Accept* in the main window, the application closes the window and updates the internal catalog.

Assuming that we have a working user interface, clicking the appropriate buttons and entering information stores the information in the object associated with the interface. Clicking the Accept button then requests a new Book object from the Book class, transfers the collected information to it, and adds it to the book catalog object. The scenario thus seems executable. However, there is a small gap here - we have a Book class and the Person class defining its major component, we also have classes implementing windows and their 'widgets' (buttons, labels, lists, input fields, and so on) - but we don't have a class to tie the user interface to the book list, borrower list, book objects, and borrower objects. In Smalltalk terminology, we have the UI (user interface) classes and the *domain* classes describing the objects in our problem domain, but we don't have the *application model* (Figure 4.5).
<figure><img src="image_325.png" /><figcaption>Figure 4.6. Smalltalk applications consist of a user interface, a domain model, and an application model.</figcaption></figure>

We will thus add another class called *LibraryCatalog*. Its responsibilities will include

* holding the description of the user interface (how the window and UI widget objects and laid out and how they communicate the information that they display or gather)

* holding information entered by the librarian before it is accepted and transferred to domain objects.

We leave it to you to verify that our classes can handle all the remaining scenarios.

### 4.3.3 Design Refinement

In this step, we must decide whether some of our classes are sufficiently similar in their behavior to warrant declaring a superclass with the shared behavior, and we must provide details for the behaviors that we identified in the previous step. In our case, the classes that we identified don't share any behaviors and there is no justification for any new superclasses. All classes, with the exception of *LibraryCatalog* have no shared behavior with any existing classes in the Smalltalk library and we will thus define them as subclasses of *Object*. Class *LibraryCatalog*, on the other hand, contains mainly behavior that is shared by all application models - it holds the description of the user interface and provides access to domain objects - and it is not surprising that VisualWorks contains an abstract class providing much of this behavior. This class is called *ApplicationModel* and *LibraryCatalog* will thus be a subclass of *ApplicationModel* (Figure 4.7).

<table><thead><tr><th>Class name: LibraryCatalog</th><th>Superclass: ApplicationModel</th></tr></thead><tbody><tr><td>Responsibilities</td><td>Collaborator classes</td></tr><tr><td>Hold description of user interface</td><td></td></tr><tr><td>Hold book information until accepted</td><td></td></tr><tr><td>Hold borrower information until accepted</td><td></td></tr></tbody></table>
<figure><img src="image_326.png" /><figcaption>Figure 4.7. CRC card of class LibraryCatalog.</figcaption></figure>

The last step is to decide whether we should refine some of the responsibilities that we identified in the previous steps. Since our domain classes are trivial information objects, all their simple behaviors are accessing behaviors that don't require any elaboration. Since we cannot implement our classes, we are thus finished.

### Example: Puzzle-a-day program

use sorted dictionary but implement it as sorted collection.

### Chapter projects

All project classes are available in the file-in code for this book.

#### Project 1: Function calculator

Re-implement Project 1 from Chapter 5 using the user interface in Figure 3.30. The project is available as Project4 in the fileout.

<caption>Figure 3.30. User interface for Project 1.</caption>

#### Project 2: The Hangman game?

Implement the Hangman game with the interface in Figure 3.31. Use the Divider and Region widgets from the canvas, beVisible and beInvisible (?) messages. Explain game. Read Chapter Input Fields, etc. first

### Project for Chapter 8

Implement the bank simulation project used as an example in Chapter 2.

### Projects for chapter 13

1.

2. Elevators

3. Port

4. Bank

1. Extend the shopping minder from Chapter 9 into the following application: The user interface consists of a single window with two single-selection list widgets and several buttons. The list on the left contains all available items and their unit prices, the list on the right contains items that the user selected and their counts. The buttons include: *Add* - asks the user for a new item name and adds it to the list of available items or increments the item's count if it is already in the list, *Get* - adds the item selected in the left list and adds it to the right list, *Delete* - subtracts one from the number of occurrences of the item selected in the right list, *Print* - prints information in the right list in the Transcript, *Close* - closes the application.
# Appendix 7 - Smalltalk Syntax

## Overview

This appendix presents the formal syntax of Smalltalk grammar - a collection of formal prescriptions for forming valid Smalltalk expressions and reading Smalltalk code correctly. The rules have been copied from the 1996 Smalltalk Draft with some modifications reflecting changes that have been decided by the committee in the meantime. The Draft contains a wealth of very interesting information going well beyond the listing of Smalltalk syntax and we recommend it for reading. With respect to the following listing, note that a draft is not a final standard and the definitions are still open to change.

### A.7.1 Syntax rules

The following rules, copied and slightly corrected from the Smalltalk Draft, use the Backus-Naur-Form (BNF) notation with a non-terminal member of the grammar (a concept being defined) on the left hand side and its definition on the right hand side of the ::= symbol. We also use

| to represent logic or

+ to represent one or more occurrences

* to represent zero or more occurrences

.. to represent all symbols from the symbol on the left to the symbol on the right

[] to represent optional symbols

() to represent grouping

<> to denote a non-terminal (a syntactic concept being defined)

‘‘ surrounds a character

“ “ surrounds a textual comment

Although the following list of rules appears long, most of the rules are auxiliary and trivial only a relatively small number of rules define substantial concepts - essentially the Expressions and Method Definition. Compared to most other languages, Smalltalk's grammar is very simple.

### Lexical primitives

<table><tr><td>&lt;character&gt;</td><td>::=</td><td>"Any character in the 7-bit ASCII character set" | "Any character in the UNICODE character set"</td></tr><tr><td>&lt;nonPrintingCharacter&gt;</td><td>::=</td><td>"Any UNICODE character interpreted as white space"</td></tr><tr><td>&lt;digit&gt;</td><td>::=</td><td>'0' .. '9'</td></tr><tr><td>&lt;digits&gt;</td><td>::=</td><td>digit+</td></tr><tr><td>&lt;uppercaseAlphabetic&gt;</td><td>::=</td><td>'A' .. 'Z' | "Any UNICODE character interpreted as uppercase alphabetic"</td></tr><tr><td>&lt;lowercaseAlphabetic&gt;</td><td>::=</td><td>'a' | .. |'z' "Any UNICODE character interpreted as lowercase alphabetic"</td></tr><tr><td>&lt;lexicalNumber&gt;</td><td>::=</td><td>&lt;digit&gt; (['.'] (&lt;letter&gt; ['-'] | &lt;digit&gt;))*</td></tr><tr><td>&lt;radixDigits&gt;</td><td>::=</td><td>(&lt;digit&gt; | &lt;uppercaseAlphabetic&gt;)+</td></tr><tr><td>&lt;number&gt;</td><td>::=</td><td>digits ['r' &lt;radixDigits&gt; | '.' &lt;digits&gt; ['e' ['-'] &lt;digits&gt;]</td></tr><tr><td>&lt;stringDelimiter&gt;</td><td>::=</td><td>""</td></tr><tr><td>&lt;nonStringDelimiter&gt;</td><td>::=</td><td>&lt;character&gt; that is not a &lt;stringDelimiter&gt;</td></tr><tr><td>&lt;string&gt;</td><td>::=</td><td>&lt;stringDelimiter&gt; (&lt;nonStringDelimiter&gt; &lt;stringDelimiter&gt; &lt;stringDelimiter&gt;)* &lt;stringDelimiter&gt;</td></tr><tr><td>&lt;nonCaseLetter&gt;</td><td>::=</td><td>'_'| "Any UNICODE character interpreted as non-case letter."</td></tr><tr><td>&lt;letter&gt;</td><td>::=</td><td>&lt;uppercaseAlphabetic&gt; | &lt;lowercaseAlphabetic&gt; | &lt;nonCaseLetter&gt;</td></tr><tr><td>&lt;identifier&gt;</td><td>::=</td><td>&lt;letter&gt; (&lt;letter&gt; | &lt;digit&gt;)*</td></tr><tr><td>&lt;keyword&gt;</td><td>::=</td><td>&lt;identifier&gt; ':'</td></tr><tr><td>&lt;commentDelimiter&gt;</td><td>::=</td><td>""</td></tr><tr><td>&lt;nonCommentDelimiter&gt;</td><td>::=</td><td>&lt;character&gt; where &lt;character&gt; is not a &lt;commentDelimiter&gt;</td></tr></table>
<table><tr><td>&lt;comment&gt;</td><td>::= &lt;commentDelimiter&gt; &lt;nonCommentDelimiter&gt; &lt;commentDelimiter&gt;</td></tr><tr><td>&lt;binaryCharacter&gt;</td><td>::= '+|'|'\|'*'|~|'|'<|'|'='|'|'@'|'%'|'|'|'|'|'&'|'?'|'!'|',<br/>| "Any UNICODE character interpreted as binary operator."</td></tr><tr><td>&lt;binarySelector&gt;</td><td>::= '-' | ('-' | &lt;binaryCharacter&gt;)* &lt;binaryCharacter&gt;</td></tr><tr><td>&lt;returnOperator&gt;</td><td>::= 'A'</td></tr><tr><td>&lt;assignmentOperator&gt;</td><td>::= ':'</td></tr><tr><td>&lt;separator&gt;</td><td>::= (&lt;nonPrintingCharacter&gt; | &lt;comment&gt;)*</td></tr></table>

## Atomic Terms

<table><tr><td>&lt;literal&gt;</td><td>::= &lt;numberConstant&gt; | &lt;stringConstant&gt; | &lt;characterConstant&gt; | &lt;symbolConstant&gt; | &lt;arrayConstant&gt; | &lt;identifier&gt;</td></tr><tr><td>&lt;numberConstant&gt;</td><td>::= ['-'] &lt;number&gt;</td></tr><tr><td>&lt;stringConstant&gt;</td><td>::= &lt;string&gt;</td></tr><tr><td>&lt;characterConstant&gt;</td><td>::= '$' &lt;character&gt;</td></tr><tr><td>&lt;hash&gt;</td><td>::= '#'</td></tr><tr><td>&lt;symbol&gt;</td><td>::= &lt;identifier&gt; | &lt;binarySelector&gt; | &lt;keyword&gt;+</td></tr><tr><td>&lt;literalSelector&gt;</td><td>::= &lt;hash&gt; &lt;symbol&gt;</td></tr><tr><td>&lt;literalSymbol&gt;</td><td>::= &lt;hash&gt; &lt;string&gt;</td></tr><tr><td>&lt;symbolConstant&gt;</td><td>::= &lt;literalSelector&gt; | &lt;literalSymbol&gt;</td></tr><tr><td>&lt;arrayConstant&gt;</td><td>::= &lt;hash&gt; ('&lt;literal&gt;'')</td></tr><tr><td>&lt;variableName&gt;</td><td>::= &lt;identifier&gt;</td></tr></table>

## Expressions

<table><tr><td>&lt;primary&gt;</td><td>::= &lt;identifier&gt; | &lt;literal&gt; | &lt;blockConstructor&gt; | &lt;subExpression&gt;</td></tr><tr><td>&lt;unarySelector&gt;</td><td>::= &lt;identifier&gt;</td></tr><tr><td>&lt;unaryMessage&gt;</td><td>::= &lt;unarySelector&gt;</td></tr><tr><td>&lt;binaryMessage&gt;</td><td>::= &lt;binarySelector&gt; &lt;primary&gt; &lt;unaryMessage&gt;*</td></tr><tr><td>&lt;keywordMessage&gt;</td><td>::= (&lt;keyword&gt; &lt;primary&gt; &lt;unaryMessage&gt;* &lt;binaryMessage&gt;*)+</td></tr><tr><td>&lt;cascadedMessage&gt;</td><td>::= ('.' | &lt;unaryMessage&gt; | &lt;binaryMessage&gt; | &lt;keywordMessage&gt;))*</td></tr><tr><td>&lt;messages&gt;</td><td>::= &lt;unaryMessage&gt;+ &lt;binaryMessage&gt;* [keywordMessage] | &lt;binaryMessage&gt;+ [&lt;keywordMessage&gt;] | &lt;keywordMessage&gt;</td></tr><tr><td>&lt;restOfExpression&gt;</td><td>::= [&lt;messages&gt; &lt;cascadedMessages&gt;}</td></tr><tr><td>&lt;expression&gt;</td><td>::= &lt;variableName&gt; (&lt;assignmentOperator&gt; &lt;expression&gt; | &lt;restOfExpression&gt;) | &lt;variableName&gt; &lt;assignmentOperator&gt; &lt;expression&gt; | &lt;primary&gt; &lt;restOfExpression&gt; | 'super' &lt;messages&gt; &lt;cascadedMessages&gt;</td></tr><tr><td>&lt;temporaries&gt;</td><td>::= ['|' &lt;temporaryList&gt; ']' | '||'</td></tr><tr><td>&lt;temporaryList&gt;</td><td>::= &lt;declaredVariableName&gt;*</td></tr><tr><td>&lt;declaredVariableName&gt;</td><td>::= &lt;variableName&gt;</td></tr><tr><td>&lt;blockConstructor&gt;</td><td>::= '[' &lt;blockDeclarations&gt; &lt;statements&gt; ']'&gt;</td></tr><tr><td>&lt;blockDeclarations&gt;</td><td>::= &lt;temporaries&gt; | &lt;blockArgument&gt;+ | ']' | &lt;temporaries&gt;</td></tr><tr><td>&lt;blockArgument&gt;</td><td>::= ':' &lt;variableName&gt;</td></tr><tr><td>&lt;statements&gt;</td><td>::= [&lt;returnOperator&gt; &lt;expression&gt; ['&'] | &lt;expression&gt; ['.' &lt;statements&gt;]]</td></tr></table>

Note: The definition of &lt;blockDeclarations&gt; has been corrected with respect to the Draft.

## Method Definition

<table><tr><td>&lt;method&gt;</td><td>::= &lt;messagePattern&gt; &lt;temporaries&gt; &lt;statements&gt;</td></tr><tr><td>&lt;messagePattern&gt;</td><td>::= &lt;keywordPattern&gt; | &lt;binaryPattern&gt; | &lt;unaryPattern&gt;</td></tr><tr><td>&lt;keywordPattern&gt;</td><td>::= (&lt;keyword&gt; &lt;identifier&gt;)+</td></tr><tr><td>&lt;binaryPattern&gt;</td><td>::= &lt;binarySelector&gt; &lt;identifier&gt;</td></tr><tr><td>&lt;unaryPattern&gt;</td><td>::= &lt;identifier&gt;</td></tr></table>

Note: The last four rules are not included in the Draft which misses a definition of &lt;messagePattern&gt;. The four rules correspond to the heading of a keyword, binary, and unary method respectively.
## Conclusion

Compared to almost all other languages, Smalltalk syntax is extremely simple because it can be reduced to the following simple points: The definition of three types of messages, the rule that a message has a receiver, the rule about combining messages into expressions and messages into statements, cascading, and the rule for the formation of literals, blocks, and methods. Unlike most other languages, Smalltalk does not have almost any reserved words with special meaning and disallowed in source code.
# Appendix 8 - Tidbits

## Overview

This appendix presents several unrelated topics that are interesting enough to be included in the book but that did not fit into the main chapters or other appendices. Consider this appendix to be a dessert.

The topics included here are material on the processing of keyboard events and how you can take advantage of it to define or redefine the behavior of selected keys, an introduction to text and fonts, a presentation of drag-and-drop in GUIs, an introduction to garbage collection, and an introduction to the classical model of the Virtual Machine.

### A.8.1 Keyboard input

In this section, we will explore the basics of Smalltalk's processing of keyboard keys and how we can take advantage of the process.

#### How it works

When you press a key on the keyboard and a Text Editor or Transcript is in control, Smalltalk first checks whether the key has a special meaning. If it does (as an example, if you press the <Delete> key), it executes the appropriate operation, if it does not, it just adds the corresponding character to the output. We will now explore how this process works and how you can take advantage of it.

The processing of user input is of course performed by the controller of the Text Editor which is an instance of ParagraphEditor. Processing of keyboard keys occurs in the editing protocol which defines response to a variety of special keys and we will use the method defining response to one of the less offensive keys to examine how the process works.

The method that we selected is backspaceKey: aCharEvent and we inserted self halt at its beginning to intercept the activation of the <Backspace> key and to open a Debugger. We then typed some text and pressed <Backspace>. The Debugger opened, and we observed the following (Figure A.8.1).

<figure><img src="image_327.png" /><figcaption>Figure A.8.1. Keyboard processing sequence.</figcaption></figure>

The existing implementation of the ParagraphEditor is based on polling. When an activity occurs, the controlActivity method in the polling loop execute two messages in the order pressKeyboard, and processMouseButtons. We will focus on pressKeyboard and leave processMouseButtons as an exercise.

Method processKeyboard first checks whether a key has indeed been pressed. If so, it sends message readKeyboard. This message check whether the character is a 'normal' character or not (<Backspace>, up or down arrow, <ESC> followed by another character, and so on). Normal characters are
added to a stream and displayed in the text view, whereas non-normal characters are 'dispatched' for further processing. This processing consists of checking ParagraphEditor's dispatch table, an instance of DispatchTable, whose function is to associate keyboard keys and their combinations with methods. A non-normal character or its combination with other characters results in the lookup of the appropriate method, which is then executed. In our case, we pressed <Backspace>, its associated method is backspaceKey:, and this method is executed next.

The essence of keyboard processing, from the developer's point of view, is the dispatch table associated with ParagraphEditor. To take advantage of the keyboard response process, we must thus understand the contents of the dispatch table. The dispatch table is associated with the ParagraphEditor class, and the initialization of the dispatch table thus happens in a class initialization method. This method is called initializeDispatchTable and the representative pieces of its definition are as follows:

initializeDispatchTable

Keyboard := DispatchTable new.
"First define default behavior."
Keyboard defaultForCharacters: #normalCharacterKey:.
Keyboard defaultForNonCharacters: #ignoreInputKey:.
"Now define non-default behavior by associating keys with methods for keys that have distinguished behavior."
"First behaviors for special keys on the keyboard."
Keyboard bindValue: #deleteKey: to: Cut. "Execute method deleteKey: if Cut (?) is pressed."
Keyboard bindValue: #pasteKey: to: Paste.
Keyboard bindValue: #backspaceKey: to: BS.
Keyboard bindValue: #backWordKey: to: Ctrlw.
"First special Ctrl keys for creating frequently needed text."
Keyboard bindValue: #displayIfTrueKey: to: Ctrlt. "Hot key for inserting ifTrue:"
Keyboard bindValue: #displayIfFalseKey: to: Ctrlf.
Keyboard bindValue: #displayDateKey: to: Ctrld. "An example of what you might do."
Keyboard bindValue: #displayColonEqualKey: to: Ctrlg.
"Now some text editing hot keys."
Keyboard bindValue: #findKey: to: Ctrls.
Keyboard bindValue: #findDialogKey: to: Ctrla.
Keyboard bindValue: #replaceKey: to: Ctrlr.
Keyboard bindValue: #replaceDialogKey: to: Ctrle.
"Now keys such as Enter, up and down arrow keys, etc."
Keyboard bindValue: #displayCRKey: to: #Enter.
Keyboard bindValue: #cursorUpKey: to: #Up.
etc.
"Next behaviors for special key combinations of a character preceded by ESC."
'<""[((' do: "Any of these preceded by ESC puts 'brackets' around the selected text."
[:char |
Keyboard
    bindValue: #encloseKey:
    to: ESC
    followedBy: char].
'sSuUbBilx+' do: "This one changes the style of the selected text."
[:char |
Keyboard
    bindValue: #changeEmphasisKey:
    to: ESC
    followedBy: char].
Keyboard "This one performs mini-formatting of code when you press ESC and then f."
    bindValue: #miniFormatKey:
    to: ESC
    followedBy: $f.
etc.

The only mystery in this definition is the meaning of symbols such as Ctrlt, Ctrlf, Cut, Paste, and BS. According to the way that these identifiers are written, they must be global variables (no, they are not of
global interest), or class variables, or keys in a pool dictionary<fnref n="1" />. It turns out that they are keys in the pool dictionary `TextConstants` because they are used by several other classes as well. When you inspect this dictionary, you will find that `Ctrl`, `Ctrlf`, `Cut`, `Paste`, and `BS` are among many characters that are assigned special names for ease of processing. As an example, `Ctrl`'s vale is the character whose hexadecimal code is "16r0014", in other words, the character whose ASCII code is 14H, often referred to as `control t`<fnref n="2" />.

Now that we fully understand how this works, we can explore how we can use it.

## How we can take advantage of it

There are three ways in which we can use this knowledge: We can use the built-in behaviors, we can modify the key combinations, and we can define new behaviors.

**Existing behaviors.** Surprisingly, much of the built-in behavior is not documented in the User Guide. As an example, did you know that if you select text and then click `ESC` followed by `i`, the selection will be italicized? If you read the above method carefully and explored the behaviors implemented by the dispatch table, you now know. The following is a summary of most of the predefined behaviors and we urge you to explore the definition for the rest and test them in the Workspace.

<table><thead><tr><th>Key or key combination</th><th>Brief description</th><th>Detailed description</th></tr></thead><tbody><tr><td colspan="3">Arrow keys</td></tr><tr><td>&lt;Ctrl&gt; &lt;a&gt;</td><td>'Find' dialog</td><td>Same effect as <i>find</i> command in the &lt;operate&gt; menu.</td></tr><tr><td>&lt;Ctrl&gt; &lt;d&gt;</td><td>Display date</td><td>Display today's date at current cursor position.</td></tr><tr><td>&lt;Ctrl&gt; &lt;e&gt;</td><td>'Replace' dialog</td><td>Same effect as <i>replace</i> command in the &lt;operate&gt; menu.</td></tr><tr><td>&lt;Ctrl&gt; &lt;j&gt;</td><td>Paste</td><td>Same effect as <i>paste</i> command in the &lt;operate&gt; menu.</td></tr><tr><td>&lt;Ctrl&gt; &lt;h&gt;</td><td>Erase character</td><td>Same effect as <i>delete</i> command in the &lt;operate&gt; menu.</td></tr><tr><td>&lt;Ctrl&gt; &lt;w&gt;</td><td>Erase word</td><td>Erase word preceding current position of cursor.</td></tr><tr><td>&lt;Ctrl&gt; &lt;i&gt;</td><td>Tab</td><td>Same effect as &lt;Tab&gt; key.</td></tr><tr><td>&lt;Ctrl&gt; &lt;f&gt;</td><td><i>ifFalse</i>:</td><td>Enter <i>ifFalse</i>: at current cursor position.</td></tr><tr><td>&lt;Ctrl&gt; &lt;g&gt;</td><td><i>:=</i> (get)</td><td>Enter <i>:=</i>: at current cursor position.</td></tr><tr><td>&lt;Ctrl&gt; &lt;t&gt;</td><td><i>ifTrue</i>:</td><td>Enter <i>ifTrue</i>: at current cursor position.</td></tr><tr><td>&lt;Ctrl&gt; ...</td><td>Control characters</td><td>According to the ASCII standard, control codes such as &lt;Ctrl&gt; &lt;I&gt; have functions such as Tab and others. See <i>TextConstants</i> and an ASCII table for definition.</td></tr><tr><td>&lt;ESC&gt; Tab</td><td>Select typed</td><td>Select (highlight) recently typed text.</td></tr><tr><td>&lt;ESC&gt; surround character</td><td>brackets toggle</td><td>Add or remove &lt;around selected text. Similar effect also for &lt;[&gt; &lt;{&gt; &lt;‘&gt; &lt;(&gt; &lt;“&gt; keys.</td></tr><tr><td>&lt;ESC&gt; &lt;f&gt;</td><td>mini-format</td><td>Format highlighted text.</td></tr><tr><td>&lt;ESC&gt; style character</td><td>change emphasis</td><td>Turn style of selection on or off. &lt;b&gt; bold, &lt;u&gt; underline, &lt;I&gt; italic, &lt;s&gt; serif, &lt;+&gt; larger font, &lt;-> smaller font, &lt;x&gt; emphasis at start of block. Lowercase letter turns emphasis on, uppercase letter turns it off.</td></tr><tr><td>F1 function key</td><td>Select typed</td><td>Select (highlight) recently typed text. Same as &lt;ESC&gt; &lt;tab&gt;</td></tr></tbody></table>

**Redefining keys.** The next thing you can do is redefine the keys defining the existing behaviors. As an example, if you are used to Microsoft Word conventions, you might want to redefine the `Paste` key to be `&lt;Ctrl&gt; &lt;v&gt;` instead of `&lt;Ctrl&gt; &lt;v&gt;`. When you look at the definition of the dispatch table above, you will see that the paste key is defined by the `Paste` pool variable and to change it, you must change the value of `Paste` in the `TextConstants` pool dictionary. One way to do this is to execute

<footnote n="1">¹ They are not, obviously, classes.</footnote>

<footnote n="2">² The first 32 ASCII codes do not have printable representation although some of them represent characters such as Tab that have effect on output. Because they have control functions, they are known as control characters and often referred to by letters of the alphabet: Code 1 is control a, code 2 is control b, etc.</footnote>
TextConstants at: #Paste put: (TextConstants at: #Ctrlv)

After this, you can check that Paste in TextConstants has now the value of "16r0016". However, this is not the end because we must now reinitialize the ParagraphEditor with this new value by

### ParagraphEditor initialize

Everything should now work. If you have an open Workspace, type something in, make a selection, copy it, and try <Ctrl> <v> to see if it performs the Paste operation. You may be surprised to find that it does not and the reason is that if the Workspace existed before you made the change, it still has the old setting associated with it. Open a new Workspace and try it, and this time it works.

Before we conclude this subsection, we must note that you cannot redefine <Ctrl> <c> because this key is permanently assigned to the Break function (open User Interrupt Exception) in the Virtual Machine.

*New behaviors and keys.* We can define new key behaviors in the same way as the old ones, as long as our new definition does not override existing ones. In this example, we will define a new hot key combination to display self halt at the cursor position because this is a frequently needed expression. We will assign this function to <Ctrl> <h> to make it easy to remember.

In our implementation, we will, of course, shamelessly steel from existing code (the term is 'reuse'). What we need to do is update the dispatch table and this must be done by editing its initialization method and then reinitializing the ParagraphEditor. When you analyze the definition of initializeDispatchTable above, you will find that we should model our addition after

Keyboard bindValue: #displayIfTrueKey: to: Ctrlt

and we thus add

Keyboard bindValue: #displaySelfHalt: to: Ctrlh

It now remains to add the new method displaySelfHalt: which we edit from the existing definition of displayIfTrueKey: as follows:

### displaySelfHalt: aCharEvent

"Replace the current text selection with the string 'self halt'."
self appendToSelection: 'self halt'

After this, we reinitialize ParagraphEditor by

### ParagraphEditor initialize

open a new Workspace, try <Ctrl> <h> - and it works! Unfortunately, there is one problem: <Ctrl> <b> is already used for the Backspace character and when we redefined it, Backspace does not delete the previous character but inserts self halt. We suggest that you change the combination from <Ctrl> <h> to <Ctrl> <b> for 'create break'. This works without problems.

In addition to binding an action to a single key, the dispatch table can also bind an action to a combination of two keys. The following statement from initializeDispatchTable shows how to do this:

Keyboard bindValue: #selectCurrentTypeInKey: to: ESC followedBy: Tab.

Finally, a note on one keyboard feature that is implemented differently. As you know, the Delete key by default acts like the Backspace key, in other words, deletes the previous character. In most word
processors, such as Word, *Delete* remove the next character. This can be changed by sending the following class message

`LookPreferences.deleteForward: true`

Since this message changes a class variable and since values of class variables are persistent, this changes the behavior of your *Delete* key permanently, until you change it back again.

## Main Lessons Learned

* Keyboard processing is handled by the controller class ParagraphEditor.

* ParagraphEditor checks each activated key and if the key (or a combination of this key and other keys) is in its dispatch table, it executes the associated action by performing the attached method.

* The dispatch table defines a number of useful undocumented behaviors.

* The method initializing the dispatch table can be edited to obtain new behaviors or to bind different keys to existing behaviors.

* The operation of `<Ctrl> <c>` is an exception because it is defined in the Virtual Machine and cannot be redefined.

* Class `LookPreferences` also plays a role in keyboard processing.

## Exercises

1. Class `DispatchTable` is a very interesting class that is the basis of keyboard mapping. Write its short description.

2. The effect of different entries in ParagraphEditor's dispatch table can be grouped into several categories. List these categories and explain how they are implemented.

3. Classify entries in `TextConstants` into categories and give one example of each.

4. How is the change of emphasis implemented?

5. Redefine other shortcut keys including `<Ctrl> <x>` to *Delete*, and `<Ctrl> <z>` to *Undo*. Try whether you can redefine `<Ctrl> <c>` to *Copy*.

6. As we noted, `<Ctrl> <d>` prints today's date. Define an escape sequence `<ESC> <d>` to open a notifier window with today's date and current time.

7. Explain the operation of the binding of a block to a function key. (Hint: The table above includes an example.)

8. Reimplement Exercise 6 to use function key F2 instead of the combination `<ESC> <d>`.

9. What is the mechanism by which class `LookPreferences` changes the behavior of the *Delete* key?

10. Our extension of hot keys to include `<Ctrl> <h>` works in the Workspace but not in the Browser. Why? Correct this shortcoming.

## A.8.2 Text and fonts

As we know, a `Text` object consists of a string and emphasis where emphasis assigns to each character in the text one or more symbols or an association, such as `#bold`, or `#(#bold #underlined)`, or `#color -> ColorValue red`. The obvious question that arises is how is this information converted to a font, size, color, and additional information needed to display the text such as line spacing, number of pixels representing a tab, and so on. To understand the mechanism and to be able to understand it, we must now introduce class `ComposedText` and its relatives.

### Class ComposedText and its relatives

For display, `Text`, must be converted to `ComposedText` as in

`aText.asComposedText`
A ComposedText contains Text and has access to a dictionary of text styles via its TextAttributes component (Figure A.8.2). The TextAttributes object does not itself contain the style dictionary but has access to a CharactersAttribute object which contains this dictionary. (In addition to an instance of CharacterAttributes, TextAttributes also contains information such as how many pixels is a tab, how many pixels separate two lines, what is the alignment of the text - centered, left aligned, and so on - etc.). The style dictionary in CharacterAttributes translates individual emphasis symbols using blocks that modify the base (default) font associated with the CharacterAttribute. (This default font is an instance of FontDescription.) Depending on how many arguments the block has, the transformation is done by

* accessing the font only or

* the font and an argument that could prescribe, for example the size of the font, or font, argument, or

* a FontPolicy object which transforms a FontDescription to an available platform font ImplementationFont. Note that the value of the dictionary might also be an array of symbols, in which case the translation is performed again using the same dictionary.

When a ComposedText is asked to display itself, as in

a ComposedText displayOn: aGraphicsContext

it uses its TextAttributes to convert tabs to pixels, calculate line spacing, and so on, and performs the translation of the emphasis of its individual characters from symbols to fonts. Using FontPolicy it then translates the obtained desired font to the nearest available ImplementationFont.

Given these principles, we can now explain how to control the font and other visible aspects of the displayed text (Figure A.8.3). A ComposedText normally uses default system TextAttributes associated with default CharacterAttributes and its associated dictionary. For most applications, the default dictionary with its definition of #color, #bold, #large, #small, #underlined, and other text styles is sufficient. When it is not sufficient, we have the following two possibilities which can be combined:

* We can associate the ComposedText with its own TextAttributes object with its own parameters, including a new CharacterAttributes object with its own custom dictionary. This dictionary can define new emphasis symbols and associate each of them with a block that transform the base font as desired. The base font itself is the font returned by message defaultQuery sent internally to the CharacterAttributes object. Some of the parameters that we might want to define for our new symbols are color, size, font family, underlining, and so on.

* Another way to introduce new fonts is to redefine the base font by defaultQuery: aFontDescription. With this approach, the blocks that transform the base font when they implement emphases start from a non-default font.
<figure><img src="image_328.png" /><figcaption>Figure A.8.2. Object diagram showing the participants in conversion of text symbols to fonts.</figcaption></figure>

<caption>Figure A.8.3. Usage diagram showing the process of conversion of text symbols to fonts.</caption>

We will now give several examples showing these basic approaches to creating new fonts and their variations.

**Example 1: Define new font color attributes – a problem requiring a one-argument emphasis block**

**Problem:** Define new emphases #red and #blue that change font color.

**Solution:** The solution does not require a new kind of font (we are just modifying attributes of the existing font) and consists of the following steps:

1. Create a new `CharacterAttributes` object from the default `CharacterAttributes`.

2. Define its `defaultQuery` to return the default font.

3. Add the `symbol -> block` entry to the `CharacterAttributes` dictionary (which already contains all predefined default emphases).

4. Create a `TextAttributes` with the new `CharacterAttributes`.

5. Assign the new `TextAttributes` as the text's new text style.
The code fragment implementing this algorithm and displaying the text in the currently active window is as follows:

```
| composedText ca ta gc |
"Get text."
composedText: = 'A text' asComposedText.
"Construct CharacterAttributes."
ca := CharacterAttributes newWithDefaultAttributes.
ca setDefaultQuery: text textStyle defaultFont.
ca at: #red put: [:fontDesc | fontDesc color:ColorValue red].
ca at: #blue put: [:fontDesc | fontDesc color:ColorValue blue].
ta := TextAttributes characterAttributes: ca.
composedText textStyle: ta.
gc := Window currentWindow graphicsContext.
composedText displayOn: gc at: 400@400.
composedText text emphasizeAllWith: #red.
composedText displayOn: gc at: 400@450.
composedText text emphasizeAllWith: #blue.
composedText displayOn: gc at: 400@500
```

### Example 2: Defining font size emphasis – a problem requiring a two-argument character attribute block

**Problem:** Define a new emphasis symbol `#size` used in size `-> 20`, such that a character assigned this emphasis is displayed with pixel size specified as its argument.

**Solution:** This problem requires a character attribute block with two argument, the second of which will be the size. The size argument will be used to assign pixel size. The general procedure is the same as in Example 1.

```
| composedText ca ta gc |
composedText: = 'A string' asComposedText.
"Construct CharacterAttributes."
ca := CharacterAttributes newWithDefaultAttributes.
ca setDefaultQuery: text textStyle defaultFont.
ca at: #size put: [:fontDesc :size| fontDesc pixelSize: (fontDesc pixelSize + size)].
ta := TextAttributes characterAttributes: ca.
composedText textStyle: ta.
gc := Window currentWindow graphicsContext.
composedText displayOn: gc at: 400@400.
composedText text emphasizeAllWith: #size -> 16.
composedText displayOn: gc at: 400@450.
composedText text emphasizeAllWith: #size -> 20.
composedText displayOn: gc at: 400@500
```

### Example 3: Display a part of the text using a different font family.

**Problem:** We are to display the string 'This string uses a different family' using font `AvantGarde` as indicated. The rest is displayed using default font and using the indicated styles.

**Solution:** We will use the same procedure as in the previous examples with the default font and a new text style called `#avantgarde`. The program is as follows:

```
| composedText ca ta gc |
composedText: = 'This string uses a different family' asComposedText.
"Construct CharacterAttributes."
ca := CharacterAttributes newWithDefaultAttributes.
ca setDefaultQuery: text textStyle defaultFont.
ca at: #avantgarde put: [:fontDesc | fontDesc family: 'avantgarde*'].
ta := TextAttributes characterAttributes: ca.
```
composedText textStyle: ta.

text text emphasizeFrom: 20 to: 36 with: #avantgarde.

gc := Window currentWindow graphicsContext.

composedText displayOn: gc at: 400@450.

Note that we used the wild card character in `'avantgarde*` because we were not sure of the exact name of the font family.

**Example 4:** Display the *whole* text using a non-default font family and combine it with various other styles.

**Problem:** We want to display the whole string `'This string uses a different font family'` using `AvantGarde` again and emphasize the whole text by underlining as shown.

**Solution:** In this case, it is better to modify the base font from which the whole string is defined. This is done by creating a new `FontDescription` object and using it as the default font for the `CharacterAttributes`. The program is as follows:

```
| composedText ca ta gc fontDescription |
composedText:='This string uses a different font family' asComposedText.
"Create a new base font description object."
fontDescription := FontDescription new
family: 'avantgarde*';
pixelSize: 16.
"Construct CharacterAttributes."
ca := CharacterAttributes newWithDefaultAttributes.
ca setDefaultQuery: fontDescription.
ca at: #avantgarde put: [:fontDesc | fontDesc family: 'avantgarde*'].
ta := TextAttributes characterAttributes: ca.
composedText textStyle: ta.
composedText text emphasizeAllWith: #underline.
gc := Window currentWindow graphicsContext.
composedText displayOn: gc at: 400@450
```

**Example 5:** Find fonts available on the current platform.

**Problem:** We may want to allow the user to select any font from a multiple choice dialog (Figure A.8.4). How do we find which fonts are available?

<figure><img src="image_329.png" /><figcaption>Figure A.8.4. Multiple dialog offering a choice from all available fonts.</figcaption></figure>
**Solution:** The 'graphic device' on which we are printing (in this case the screen) knows about available fonts. A possible solution is as follows:

```
| fontFamilies fontFamily |
"Collect all available font families."
fontFamilies := (Screen default defaultFontPolicy availableFontSets collect:
                  [:fontDesc | fontDesc family]) asSet asSortedCollection.
"Allow user to select a family."
fontFamily := Dialog choose: 'Which font do you want?'
                  fromList: fontFamilies
                  values: fontFamilies
                  lines: 8
                  cancel: [#noChoice]
```

**Example 6:** Allow the user to select a style and display the stylized text in the current window.

**Problem:** Use the multiple choice window from the previous example to choose a font family from all families available on the current platform, and display text using this family.

**Solution:** The principle of the solution is to use the collection of font families to add new emphases to the dictionary. The program is as follows:

```
| fontFamilies fontFamily ca composedText ta gc |
composedText := 'Experimental text.' asComposedText.
"Get available font families."
fontFamilies := (Screen default defaultFontPolicy availableFontSets
                  collect: [:fontDesc | fontDesc family]) asSet asSortedCollection.
"Construct CharacterAttributes."
(ca := CharacterAttributes newWithDefaultAttributes)
 setDefaultQuery: composedText textStyle defaultFont.
"Create dictionary with all font styles."
fontFamilies do: [:family | ca at: family asSymbol put: [:fontDesc | fontDesc family: family]].
"Let user select a font family."
fontFamily := Dialog choose: 'Which font do you want?'
                  fromList: fontFamilies
                  values: fontFamilies
                  lines: 8
                  cancel: [#noChoice].
ta := TextAttributes characterAttributes: ca.
composedText textStyle: ta;
text emphasizeAllWith: fontFamily asSymbol.
gc := Window currentWindow graphicsContext.
composedText displayOn: gc at: 400@500
```

**Example 7: Controlling font in a text editor widget**

**Problem:** Implement a window with a text editor widget and an `<operate>` menu with command *font* that allows the user to select any platform font for the currently highlighted text. The *font* command should open a multiple choice window as in the previous example, from which the font selection is made.

**Solution:** We will reuse the techniques from previous examples. The only new aspect of this problem is how to force the new emphasis on the selection in the text editor widget and this task is performed simply by changing the emphasis of the current text editor selection, assigning it as the new selection, and invalidating the widget. The methods implementing the application are as follows:

*Initialization*

*initialize*

"Define context of the text editor widget."
text := Array comment asComposedText asValue

### postBuildWith: aBuilder

"Create new TextAttributes with all platform fonts."
| ca ta |
fontFamilies := (Screen default defaultFontPolicy availableFontS
  collect: [:fontDesc | fontDesc family]) asSet asSortedCollection.
ca := CharacterAttributes newWithDefaultAttributes.
ca setDefaultQuery: text value textStyle defaultFont.
fontFamilies do: [:family | ca at: family asSymbol put: [:fontDesc | fontDesc family: family]].
ta := TextAttributes characterAttributes: ca.
widget := (self builder componentAt: #textWidget) widget.
widget textStyle: ta

### Menu

### menu

"Extend built-in text editor menu."
| mb |
mb := MenuBuilder new.
mb addDefaultTextMenu;
  line;
  add: 'font family' -> #fontFamily;
  add: 'font size' -> #fontSize.
^mb menu

where command *font family* is implemented by

### fontFamily

"Let user select a font family and redisplay the selection with the new font."
| fontFamily selection |
选中 selection
选中 (selection := widget controller selection) empty? ifTrue: [^self].
fontFamily := Dialog choose: 'Which font family do you want?' fromList: fontFamilies values: fontFamilies lines: 8 cancel: [nil] isNil ifTrue: [^self].
self applyNewEmphasis: fontFamily asSymbol onText: selection

which uses

### selectFontFamily

"Let user select a font family."
^Dialog choose: 'Which font do you want?' fromList: fontFamilies values: fontFamilies lines: 8 cancel: [#noChoice]

and command *font size* is implemented by

### fontSize

"Let user select a font family and redisplay the selection with the new font."
| fontSize selection |
选中 (selection := widget controller selection) empty ifTrue: [^self].
(fontSize := Dialog choose: 'Which font size do you want?' fromList: #(#small #normal #large) values: #(#small #normal #large) lines: 3 cancel: [nil] isNil ifTrue: [^self]. self applyNewEmphasis: fontSize onText: selection. widget invalidate

Finally, the method that applies emphasis and refreshes the widget is

applyNewEmphasis: aSymbol onText: aText
"Emphasize current selection with chosen emphasis."
aText emphasizeAllWith: aSymbol.
widget controller replaceSelectionWith: aText.
widget invalidate

## Closing notes

### FontPolicy

You might be wondering how `FontPolicy` which converts the desired font to an available font does this work. The principle is that if it does not find the desired font, it takes the parameters of the desired font (an instance of `FontDescription`) and compares them with the parameters of available fonts, and finds one that matches the desired font most closely. In doing this, it applies various weighting coefficients to all parameters as explained in the class comment whose essential part is as follows:

I represent a policy mapping `FontDescriptions` to actual `ImplementationFont`s available on a particular device. Mapping is done by assigning weights to the various properties that a `FontDescription` can have, and using those weights to assign a quality value to each of the available fonts as it is compared to a font request. A quality value of 0 indicates an exact match. A high quality value indicates a poor match. Any concrete font whose quality is greater than the policy's tolerance is removed from consideration.

Assigning weights can be somewhat tricky. Perhaps the easiest approach is to start by choosing a default tolerance (for example, the system default is 9), and then choose the other weightings relative to that. For example, the default system assumes that the size of characters and whether they are fixed width is moderately important, so they have weights of 3. Boldness is a little less important, and serifness even less so. The name of a font is very specific, so it's given a very high weight of 10, because the user probably has very high expectations of seeing a particular font.

Note that you can be easily redefine the weighting attributes or the whole scheme of font matching if you wish to do so. In fact, you may want to redefine the whole font management architecture if you find it unsatisfactory, for example for some of the reason mentioned in the following notes.

### Notes on TextAttributes

Our presentation implies that each `ComposedText` has exactly one `TextAttributes`. Since this object defines properties that apply not only to individual characters but also to the text as a whole, the whole object is displayed with the same alignment (centered, left aligned, etc.), the same line separation, and so on. If this is not desirable, the text must be divided into sections of `ComposedText` elements with their own parameters.

Note also that the default value of `TextAttributes` is shared by all `ComposedText` objects that use it. As a consequence, changing its parameters changes text attributes for all `ComposedText` objects
that use it. When defining new text styles, a new instance of `TextAttributes` should thus be created – as we have been doing all along. `textattr` shared – make copy

Finally, a note on emphases and the attributes dictionary. If an undefined emphasis (one that does not appear as a key in the attributes dictionary) is encountered during display, this emphasis is ignored. If a sequence of conflicting emphasis is encountered (such as a sequence of emphases specifying different font sizes), the last one is applied.

## Exercises

1. We mentioned that the fact that the whole `ComposedText` object shares the same `TextAttributes` may be too limiting. Since text editor widgets are designed to use a single `ComposedText` object as their model, this imposes limits on the extendibility of text editor widgets. The easiest way to obtain a window with sufficient text processing power thus seems to be to use subviews and appropriately extended existing views supporting `ComposedText` display - the `ComposedTextView` view, and the `ParagraphEditor` controller. Use this approach to create a window with a subview that allows the user to control the font family, pixel size, color, and other text parameters via `<operate>` menu commands.

2. Modify the implementation from Exercise 1 to implement font control using an interface similar to Microsoft window font controls.

3. Extend the above exercises to allow simple drawing. This exercise is better suited for a project.

4. Extend the previous exercise to allow 'pluggable' drawing tools selectable from a menu. This exercise is also better suited for a project.

### A.8.3. Drag-and-Drop

Drag and Drop is the familiar process of selecting an item in a source widget by pressing the `<select>` mouse button over an item, dragging the mouse pointer over another widget with the button pressed, and dropping the data into a target widget by releasing the mouse button over it. The action is usually accompanied by a visual feedback, typically by changing the shape of the mouse pointer as it moves over windows and widgets. In VisualWorks, the source may be a list, and the target may be a window or any widget.

We will give a simple example of the implementation of drag and drop but first the principles. The operation involves the cooperation of the following new classes:

* **DragDropManager**: An instance of this class coordinates the whole drag and drop operation from the moment the user presses the `<select>` button over a source widget, to the moment the button is released over a target.

* **DragDropContext** is carried by **DragDropManager** and contains all information necessary for the operation including the dragged data (an instance of **DragDropData**), information about cursor shape, and information stored in it by a drop target, usually the one that was most recently entered. An instance of this class is used as the argument of messages sent by **DragDropManager** as it carries out the drag and drop operation and provides access to all necessary drag and drop information.

* **DragDropData** holds data to be transferred and information about the drag origin widget. The data is often held in an **IdentityDictionary** which makes it possible to story any number of items and access them by arbitrary keys. It also contains a key object, a **Symbol** identifying the nature of the data for use by the target.

* **DropSource** is used to provide information about cursor shapes at various stages during the operation.

* **ConfigurableDropTarget** is an object representing the target widget. It is automatically created by the **UIBuilder** when a widget's properties specifies that the widget is a drag and drop target. When the mouse pointer moves into this widget's bounds, the **DragAndDropManager** recognizes this and sends mouse motion-related messages to it.

The basic operation of drag and drop is as follows (Figure A.8.5):
1. User presses `<select>` button over a widget identified as a source via its *DragStart* property.

2. The source widget sends its *DragStart* message to the application.

3. The *DragStart* method is responsible for creating a *DragDropData* instance containing the data and possibly other information such as a *Symbol* identifying the nature of the data. The method also creates a *DropSource* object containing information about entry effects. Finally, the *DragStart* method must create an instance of *DragDropManager* which will be responsible for the whole drag and drop. The *DragDropManager* now takes over.

4. As the user moves the mouse with the pressed button, the *DragDropManager* monitors the windows and widgets over which the mouse pointer is passing. If the mouse passes over a window or widget set up as a drop target via its properties, it sends the following messages to the application model:

* a designated *entry* message (a specified property of the widget) – when it enters a target widget

* a designated *over* message (a specified property of the widget) – when the mouse pointer moves while over a target widget

* a designated *exit* message (a specified property of the widget) – when it exits a target widget
All these messages have a *DragContext* as their argument and obtain information such as the data and the key *Symbol* from it. They typically provide visual feedback by changing the cursor or highlighting the widget.

5. When the user releases the button over a target window or widget, *DragDropManager* sends a designated *Drop* message (a specified property of the widget) to the application. This message typically processes the data and provides visual feedback.

6. The drag and drop operation is finished and the *DragDropManager* is released.
<figure><img src="image_330.png" /><figcaption>Figure A.8.5. Essence of the Drag and Drop process.</figcaption></figure>

After this introduction, we will now present a simple example of a drag and drop user interface.

### Example: Library Cataloguing Tool

**Problem:** Assume that a part of the process of cataloguing new books is classifying them as 'regular' books and 'reserve' books. Assume that all new books are entered into a list, and a 'reserve clerk' examines each book and classifies it manually as regular or reserve. Our task is to implement a preliminary version of a tool to computerize this task (Figure A.8.6). To use this tool, the clerk first clicks a book title in the list which displays its information, and then drags the title to one of the list below. At this point, the book is removed from the original list.
<figure><img src="image_331.png" /><figcaption>Figure A.8.6. Book classification tool.</figcaption></figure>

### Design

Assume that we already have a suitable class Book to represent individual books. To keep things simple for this example, we will hold the new books and the classified books in the application model's list aspect variables `newBooks`, `regularBooks`, and `reserveBooks`. The application model class will be called `BookClassifier`.

For the sake of this example, we will assume that the new books list already exists (we will initialize it to a few books during initialization) and the only responsibility of `BookClassifier` will be the drag and drop operation. In addition to the collection instance variables, `BookClassifier` will have aspect variables `author`, `title` and `year` for the input fields.

### Implementation

Draw the user interfaceWe specified the following properties for the three lists:

**New Books** – drop source:
* Drag OK: #dragOK
* Drag Start: #dragStart
* Notification:
* Change: #newSelection - equivalent to sending `onChangeSend: newSelection to: self` on initialization

**Regular Books** – drop target:
* Entry: #entry
* Over: #over
* Exit: #exit
* Drop: #addRegularBook

**Reserve Books** – drop target:
* Entry: #entry
Over: #over

Exit: #exit

Drop: #addReserveBook

Note that we specified the same Entry, Over, and Exit methods for both drop target lists because we want the same visualization behavior for both: Both will change the cursor in the same way on entry and on exit.

We will now implement initialization and all the above methods.

initialize

"Create test list of new books and assign it to the New Books list widget."

| books authors titles years |

books := SortedCollection sortBlock: [:x:y | x author < y author].

authors := #('Orwell' 'Steinbeck' 'Wright' 'Moliere' 'Carre' 'Ross' 'Turgenev' 'Crane' 'Richardson').

titles := #'(Nineteen Eighty-Four' 'Of Mice and Man' 'Black Boy' 'Tartuffe' 'The Little Drummer Girl'

'As For Me and My House' 'Fathers and Sons' 'The Red Badge of Courage' 'Wacousta').

years := #(
1980 1975 1960 1670 1992 1980 1985 1970 1977
)

1 to: authors size do: [:index | books add: (Book
author: (authors at: index)
title: (titles at: index)
year: (years at: index))].

self newBooks list: books

Now the drag and drop related methods, starting with the drag source widget. The dragOK method is executed when the user presses <select> over the widget. It returns true if drag is OK, false otherwise.

dragOK: aController

"Allow drag operation only if the list is not empty."

^newBooks list.isEmpty not

If dragOK returns true, the following method sets up a DragDropManager and starts the drag operation. All the messages in the method are required for drag and drop to work.

dragStart: aController

"Create and strt a dd with data necessary for visualization and data drop."

| data ds dm |

data := DragDropData new.

data clientData: newBooks selection.

data contextWindow: self builder window.

data contextWidget: aController view.

data contextApplication: self.

ds := DropSource new.

dm := DragDropManager withDropSource: ds withData: data.

dm doDragDrop

Proceeding now to the target lists, we will first define the entry, over, and exit methods that respond to the passing of the mouse into, over, and out of the widget. They all return a Symbol which is used by DropSource to select the appropriate cursor. This value – an *effect symbol* – has the following default values: #dropEffectMove, #dropEffectNone, #dropEffectCopy, and #dropEffectNormal, associated with special cursors; custom cursors may be defined for user-defined symbols as well. Our definitions don't do anything except for returning the appropriate effect symbol:

entry: aDragContext

"Show that it is possible to move the object to this list."

^#dropEffectMove

over: aDragContext
"Show that it is possible to move the object to this list."
^#dropEffectMove

**exit: aDragContext**

"Show that no drop operation is possible outside the list."
^#dropEffectNone

Finally, we will define the drop method when the user executes the drop operation by releasing the mouse button. The method returns the effect symbol defining the shape of the cursor after the operation. For the Regular Books list the method is

**addRegularBook: aDragContext**

"User released mouse button. Get data and add it to this list, remove the item from the New Books list."

| book |
book := aDragContext sourceData clientData.
regularBooks list: ((regularBooks list) add: book; yourself).
self removeBook: book.
^#dropEffectNone

and addReserveBook: is similar. Both methods share removeBook: which is defined as follows:

**removeBook: aBook**

"User dropped aBook into another book list, remove it from the New Books list."
newBooks list: ((newBooks list) remove: aBook; yourself).
title value: "".
author value: "".
year value: ""

This completes the implementation and the program is now fully functional. As mentioned in the introduction, this example shows only the basic features of Drag and Drop and we encourage you to study the more involved examples in the Cookbook, and to implement the exercises.

## Main Lessons Learned

* Drag and drop involves widgets whose properties define them as drop source or drop targets.

* A widget may be a drop source, a drop target, both, or none of these.

* Drop source properties include the name of a method that determines whether it is OK to perform a drag and drop, and a method that creates a DragDropManager with appropriate data to realize the operation.

* Drop target properties include the name of methods that determine what happens when the mouse pointer enters the widget, moves inside it, and leaves it. They all return an effect symbol which determines the new shape of the mouse cursor. Another method is activated when the user releases the mouse; it executes the drop action and returns an effect symbol.

* The Notification property of a widget may be used with the same effect as ONCHANGESEND: to: during initialization.

## Exercises

1. Implement the example from the text.

2. We

3. Extend the example by allowing the user to drag a book from Regular Books to Reserve Books and vice versa. This is possible because a widget may be both a source and a target.

4. Extend the example by allowing the user to drag a book from Regular Books or Reserve Books to a garbage bin. (A label may be an image and a drop widget.)

5. Add a list of Archived Books reserved for old books. Only a book published before 1800 may be dropped into Archived Books. (Hint: Calculate a Symbol - #old or #notOld - when a book is picked, assign it as key to the DragDropContext, and use it to make a decision.)
### A.8.4 The Virtual Machine

Every programming language that allows its users to create objects dynamically must have a mechanism for removing objects that are no longer needed. Otherwise, many applications would soon run out of memory. According to the mechanism for destroying unneeded objects, programming languages can be divided into two groups: those that destroy unneeded objects automatically (such as Smalltalk, Java, and LISP), and those that require the programmer to destroy unneeded objects by explicit destructor construction (such as C++). Modern programming practices generally prefer automatic garbage collection.

Automatic garbage collection is several decades old and underwent a lot of evolution because its inefficient implementation may render it practically unusable. In terms of strategies, there are two basic approaches to identifying inactive objects (also known as 'corpses': One is to associate a count of existing references for every new object and increment or decrement the count when a reference to the object is created or dropped. The other approach is to establish a part of the system as the 'root' and decide whether an object is live by attempting to trace a chain of references from the roots of the system to the object. Both strategies are recursive in that the marking of referenced objects requires proceeding down to object components until finding a primitive object with no components, and that incrementing or decrementing the count also requires going down to the primitive objects. The disadvantage of reference counting is that it must be done whenever an object is created, destroyed, or assigned and this approach is thus inefficient and not used any more.

In addition to an algorithm for distinguishing live objects from corpses, we also need a storage strategy and a strategy for deciding whether all objects need to be examined or not, and if all objects are not examined on every garbage collection pass then which ones are and which ones are not. As the experience with garbage collection grew, it was discovered that a very large majority of objects created during execution have a very short life span while other objects are very stable. This means that once an object remains live long enough, it will probably remain so for a very long time and testing it is a waste of time. On the basis of this finding, modern garbage collection techniques divide objects into several categories, store them in separate memory spaces, and deal with them separately.

After this general introduction, we will now describe how garbage collection is performed in VisualWorks. Our description is based on comments and other information available in class ObjectMemory which is responsible for performing garbage collection, and class MemoryPolicy which defines the garbage collection strategy and parameters.

Garbage collection in VisualWorks

### A.8.5 Garbage collection

#### Conclusion

#### Important classes introduced in this chapter

Classes whose names are **boldfaced** are very important, classes whose names are printed in *italics* are less important, classes whose names are printed in regular font are not of much interest.

ConfigurableDropTarget, DispatchTable, DragDropContext, DragDropData, DragDropManager, DropSource, LookPreferences, ParagraphEditor,