Previous Table of Contents Next


The life cycle of a Smalltalk temporary variable or argument does not necessarily follow the normal FIFO pattern of ALGOL-like block-structured languages. Because a block closure can capture a reference to a temporary variable or argument, such variables must continue to exist as long as the block closure exists. This period can extend after the return from the method or block invocation that created the variable or argument.

Just as methods can declare temporary variables, blocks can also declare local temporary variables. The syntax is similar to that used for methods. The local variables names for a block immediately follow the block arguments and are enclosed in vertical bars. Consider this code, for example:

  [:each |
      | temp |
      temp := each size + 15.
      Array new: temp].
  [| size tempArray| “ a no argument block with temps”
      size := 10.
      tempArray := Array new: size.
      1 to: size do: [:i| tempArray at: i put: ‘initial   string’]].

4.5. Computed Message Selectors

In all the examples used to this point, the message selector for each message send has been specified as part of the syntax of a message send expression. In some situations, it is useful to dynamically change the message selector that will be used at some point in a program. Consider the case of a class that represents menus in a graphical user interface. Each instance of the class would represent a particular menu, which consists of a number of labeled items. A message to the menu object would cause a graphic representation of the labels to be displayed and would accept user input to select one of the items. Upon selection of an item, the menu object would send a message to some object indicating which item was selected. The following partial class definition presents the skeleton of the definition of such a class:

Class Name Menu
Superclass Object
Instance Variables labels
Instance Methods
label: anArray
“Initialize a menu object. The argument is an array of strings that
specify the labels of the menu.”
| c |
labels size > 5 ifTrue: [self error: “Too many items for menu’].
labels := anArray
selectNotifying: agent
“display the menu, get the users selection, and notify the agent
according to which item was selected”
| item |
self display.
item := self getSelection.
self hide.
item > 0 ifTrue: [self notify: agent with: item]
display
“Private - Present a graphic display of the menu items”
...
getSelection
“Private - Interact with the use to determine which item is
selected. Return the index of the selected label. Return 0 if
no selection was made.”
...
hide
“Private - Remove the graphic display of the menu items”
...
notify: agent with: labelIndex
“Private - Send a message to the agent object that identifies the
item that was selected”
labelIndex = 1 ifTrue: [^agent item1Selected].
labelIndex = 2 ifTrue: [^agent item2Selected].
labelIndex = 3 ifTrue: [^agent item3Selected].
labelIndex = 4 ifTrue: [^agent item4Selected].
labelIndex = 5 ifTrue: [^agent item5Selected].

A programmer would create an instance of this class by using an expression such as the following:

  editMenu := Menu new labels: #(‘cut’ ‘copy’ ‘paste’).

At the point in the program where this menu should be presented to the user, the programmer might code this line:

  editMenu selectNotifying: editorObject.

The object that was the value of editorObject would then be sent an item n Selected message that indicated which menu item was actually selected.

There are several undesirable properties of this class. The most obvious problem is that its menus can have only a fixed number of items. This limitation comes from the need to use a separate message expression to send each of the possible item-selected messages. This requirement, in turn, arises from the manner in which message selectors are syntactically specified in a message expression.

Another undesirable property is that the editorObject that is notified of the selection must have been written such that it implements methods named item1Selected, item2Selected, and item3Selected. This closely couples the implementation of the editorObject and the Menu class. Such coupling would make it difficult to modify the method of selection used by the program or to reuse the editor object in a different program. It would be more desirable for the editor object to receive messages with names such as cut, copy, and paste when a menu item is selected. Of course, other instances of Menu that notified other types of objects would prefer to use other problem-specific message selectors to notify of selection.

What is needed to solve these problems is a means to parameterize the method selector that is sent to notify the agent of the selection. This can be accomplished through the use of blocks or message selector objects.

A block is an object that represents the capability to send the message cut to an arbitrary object that is passed as an argument when the block is evaluated. Consider the following block:

  [:obj| obj cut]

This type of block is much more flexible than a simple message expression. As an object, it can be assigned to variables and aggregated into data structures. For example, three such blocks could be collected into an array such as this one:

  selectionMessages := Array new: 3.
  selectionMessages
      at: 1 put: [:obj| obj cut];
      at: 2 put: [:obj| obj copy];
      at: 3 put: [:obj| obj paste].


Previous Table of Contents Next