One of the most unusual aspects of Smalltalk is that statements in the language do not provide the control structures. Instead, they are formed with the fundamental object-oriented paradigm: message passing.
Blocks provide a way to collect expressions into groups. These groups can be used to build execution control statements.
A block is an unnamed literar object that contains a sequence of expressions. Blocks are instances of the class block. A message can be sent to a block by placing the message immediately after the block.
A block is specified in brackets, with its expression components separated by periods, as in
[index <- index + 1. sum <- sum + index]
The expression in a block are deferred actions because they are not executed when encountered; rather they are executed only when the block is sent the unary messagevalue, which is defined in the class Block. For example
[sum <- sum + index] value
sends the message value to the block, causing its execution. When a block execution is completed, the value of the last expression in the block is returned.
Blocks can be assigned to variables and executed by sending the value message to the variable, given the expression
addIndex <- [sum <- sum + index}
The message expression
addIndex value
causes index to be added to sum. This message expression could also be assigned to a variable, as follows:
addIndex <- [sum + index]
sum <- addIndex value
Blocks are always executed in the context of their definition, even when they are sent as parameters to a different object.
Blocks can be thought of as procedure declarations that may appear anywhere. Like procedures, blocks can have parameters. Block parameters are specified in a section at the beginning of the block that is separated from the remainder of the block by a vertical bar (|). The formal parameter specifications require a colon to be attached to the left end of each parameter. Because there are no declared types, the specifications include only the formal parameter names, which are listed without any separating punctuation. As an example of a block with parameters, consider the following:
[:x :y | sum <- x + 10. total <- sum * y]
Blocks provide a means of collecting expressions, so they are a natural way to form control structures in Smalltalk.
One measure of simplicity is the amount of text required to take advantage of a language feature. Smalltalk's Blocks and Java's "anonymous" inner classes are comparable language features, each aimed at customizing an application with "pluggable" behavior at run time. We can get a sense of each language's simplicity by looking at the amount of text required to use these features.
First here is a Smalltalk Block used to count the number of times it has been evaluated.
| count | count := 0. [count := count + 1]
Now the equivalent Java Anonymous Inner Class.
public interface Counter { public int current(); } final int[] count = new int[1]; return new Counter() { public int current() { return count[0] += 1; }};
The first restriction is that an "anonymous" inner class actually requires a name, i.e. a definition of an interface or class like Counter. That definition is going to have to exist in a file somewhere, be incorporated into a Makefile or an IDE's list of known definitions, etc. So there is nothing very "anonymous" about an anonymous class in Java.
The second restriction to notice is that an inner class can only refer to variables from the outer lexical scope if those variables are declared to be final. This keyword tells the compiler that the binding of that variable cannot be modified at runtime.
In order for an instance of an inner class to modify an outer variable, the trick is to declare the variable to be an array. Then the binding of the array is final but the element of the array is not!