GemStone Smalltalk Syntax

Previous chapter

This appendix outlines the syntax for GemStone Smalltalk and introduces the important kinds of GemStone Smalltalk objects.

A.1 GemStone and ANSI Smalltalk

GemStone’s programming language, GemStone Smalltalk, is a dialect of the Smalltalk programming language. The Smalltalk language standard is defined by an ANSI Smalltalk standard. While GemStone follows this standard, there are places where either for historical reasons or by choice, GemStone Smalltalk does not follow the ANSI standard.

Some known places in which GemStone Smalltalk does not conform to the ANSI standard:

A.2 GemStone Smalltalk

Every object is an instance of a class, taking its methods and its form of data storage from its class. Defining a class thus creates a kind of template for a whole family of objects that share the same structure and methods. Instances of a class are alike in form and in behavioral repertoire, but independent of one another in the values of the data they contain.

Classes are much like the data types (string, integer, etc.) provided by conventional languages; the most important difference is that classes define actions as well as storage structures. In other words, Algorithms + Data Structures = Classes.

Smalltalk provides a number of predefined classes that are specialized for storing and transforming different kinds of data. Instances of class Float, for example, store floating-point numbers, and class Float provides methods for doing floating-point arithmetic. Floats respond to messages such as +, -, and reciprocal.

Instances of class Array store sequences of objects and respond to messages that read and write array elements at specified indices.

The Smalltalk classes are organized in a treelike hierarchy, with classes providing the most general services nearer the root, and classes providing more specialized functions nearer the leaves of the tree. This organization takes advantage of the fact that a class’s structure and methods are automatically conferred on any classes defined as its subclasses. A subclass is said to inherit the properties of its parent and its parent’s ancestors.

How to Create a New Class

Classes are created using a number of class creation methods, defined on the class Class. For example, following message expression makes a new subclass of class Object, the class at the top of the class hierarchy:

Object 	subclass: 'Animal'
	instVarNames: #()
	classVars: #()
	classInstVars: #()
	poolDictionaries: {}
	inDictionary: UserGlobals

This subclass creation message establishes a name (’Animal’) for the new class and installs the new class in a Dictionary called UserGlobals. The String used for the new class’s name must follow the general rule for variable names — that is, it must begin with an alphabetic character and its length must not exceed 1024 characters. Installing the class in UserGlobals makes it available for use in the future—you need only write the name Animal in your code to refer to the new class. For more on class creation, see Chapter 2.

Case-Sensitivity

GemStone Smalltalk is case-sensitive; that is, names such as “SuperClass,” “superclass,” and “superClass” are treated as unique items by the GemStone Smalltalk compiler.

Statements

The basic syntactic unit of a Smalltalk program is the statement. A lone statement needs no delimiters; multiple statements are separated by periods:

a := 2.
b := 3.

In a group of statements to be executed en masse, a period after the last statement is optional.

A statement contains one or more expressions, combining them to perform some reasonable unit of work, such as an assignment or retrieval of an object.

Comments

GemStone Smalltalk usually treats a string of characters enclosed in quotation marks as a comment—a descriptive remark to be ignored during compilation. Here is an example:

"This is a comment."

A quotation mark does not begin a comment in the following cases:

  • Within another comment. You cannot nest comments.
  • Within a string literal (String Literals). Within a GemStone Smalltalk string literal, a “comment” becomes part of the string.
  • When it immediately follows a dollar sign ($). GemStone Smalltalk interprets the first character after a dollar sign as a data object called a character literal (Character Literals).

A comment terminates tokens such as numbers and variable names. For example, GemStone Smalltalk would interpret the following as two numbers separated by a space (by itself, an invalid expression):

2" this comment acts as a token terminator"345

Expressions

An expression is a sequence of characters that Smalltalk can interpret as a reference to an object. Some references are direct, and some are indirect.

Expressions that name objects directly include both variable names and literals such as numbers and strings. The values of those expressions are the objects they name.

An expression that refers to an object indirectly by specifying a message invocation has the value returned by the message’s receiver. You can use such an expression anywhere you might use an ordinary literal or a variable name. This expression:

2 negated

has the value (refers to) -2, the object that 2 returns in response to the message negated.

The following sections describe the syntax of GemStone Smalltalk expressions and tell you something about their behavior.

Kinds of Expressions

A GemStone Smalltalk expression can contain a combination of the following:

  • a literal
  • a variable name
  • an assignment
  • a message expression
  • an array constructor
  • a path
  • a block

The following sections discuss each of these kinds of expression in turn.

Literals

A literal expression is a representation of some object such as a character or string whose value or structure can be written out explicitly. The kinds of GemStone Smalltalk literals are:

  • numbers
  • characters
  • strings
  • symbols
  • arrays of literals

Numeric Literals

In Smalltalk, literal numbers look and act much like numbers in other programming languages. Like other Smalltalk objects, numbers receive and respond to messages. Most of those messages are requests for arithmetic operations. In general, Smalltalk numeric expressions do the same things as their counterparts in other programming languages. For example:

5 + 5

returns the sum of 5 and 5.

A literal floating point number must include at least one digit after the decimal point:

5.0

You can express very large and very small numbers compactly with scientific notation. To raise a number to some exponent, simply append the letter “e” and a numeric exponent to the number’s digits. For example:

8.0e2

represents 800.0. The number after the e represents an exponent (base 10) to which the number preceding the e is to be raised. The result is always a floating point number. Here are more examples:

1e-3 represents 0.001 
1.5e0 represents 1.5

The literal numeric type GemStone/S 64 Bit supports are:

  • “e”, “E”, “d” and “D” for floating point literals (SmallDouble or Float)
  • “f” and “F” for DecimalFloat literals
  • “s” for ScaledDecimal literals
  • “p” for FixedPoint literals

For details, see GemStone Smalltalk Lexical Tokens.

To represent a number in a nondecimal base literally, write the number’s base (in decimal), followed by the radix “r” or character "#", and then the number itself. Here, for example, is how you could write octal 23 and hexadecimal FF:

8#23 
16rFF

The largest radix available is 36.

Character Literals

A Smalltalk character literal represents a character, such as one of the symbols of the alphabet. To create a character literal, write a dollar sign ($) followed by the character’s alphabetic symbol. Here are some examples:

$b  $B  $4  $?  $$

If a nonprinting ASCII character such as a tab or a form feed follows the dollar sign, Smalltalk creates the appropriate internal representation of that character.

GemStone Smalltalk interprets this statement, for example, as a representation of ASCII character 32:

$ . "Creates the character representing a space (ASCII 32)"

In this example, the period following the space acted as a statement terminator. If no space had separated the dollar sign from the period, GemStone Smalltalk would have interpreted the expression as the character literal representing a period.

String Literals

Literal strings represent sequences of characters. They are instances of the class String, described in Chapter 4, “Collection and Stream Classes”.A literal string is a sequence of characters enclosed by single quotation marks. These are literal instances of String:

'Intellectual passion drives out sensuality.'
'A difference of taste in jokes is a great strain on the affections.'

When you want to include apostrophes in a literal string, double them:

'You can''t make omelettes without breaking eggs.'

GemStone Smalltalk faithfully preserves control characters when it compiles literal strings. The following example creates a String containing a line feed (ASCII 10), the end-of-line character:

'Control characters such as line feeds are significant in literal strings.'

Strings may hold characters with values up to 255, that is, characters that can be representing in a single byte. Characters themselves may have values much higher. If a string includes any characters larger than 255, it is converted to a DoubleByteString. If any of the characters require more than two bytes, it becomes a QuadByteString. For example, this is a DoubleByteString:

'Škoda'

Symbol Literals

A literal Symbol is similar to a literal String. It is a sequence of characters preceded by a pound sign (#). For example:

#stuff
#nonsense
#may_24_thisYear

Literal Symbols specified in this way must be legal identifiers or keywords: they must begin with a letter, contain only alphanumeric characters, underscore, and colon. A Symbol can contain other characters, or start with a number: in this case, they must be preceded by a pound sign (#) and must also be delimited by single quotation marks. For example:

#'Gone With the Wind'

As with strings that contain characters that require more than a byte to represent, DoubleByteSymbol and QuadByteSymbol are used for symbol literals that include characters with values over 255.

Array Literals

Arrays can hold objects of any type, and they respond to messages that read and write individual elements or groups of elements.

A literal Array can contain only other literals—Characters, Strings, Symbols, other literal Arrays, and three “special literals” (true, false, nil). The elements of a literal Array are enclosed in parentheses and preceded by a pound sign (#). White space must separate the elements.

Here is an Array that contains two Strings, a literal Array, and a third String:

#('string one' 'string two' #('another' 'Array') 'string3')

The following Array contains a String, a Symbol, a Character, a Number, and a Boolean:

#('string one' #symbolOne $c 4 true)

ByteArray literals are similar, but may only hold SmallIntegers in the range 0 to 255, and use square brackets instead of parenthesis.

For example:

#[99 97 116]

Besides Array literals, you may also specify Array constructors in your code, which are used similarly, but follow quite different rules. For a discussion of array constructors, Array Constructors.

Variables and Variable Names

A variable name is a sequence of characters of either or both cases. A variable name must begin with an alphabetic character or an underscore (“_”), but it can contain numerals. Spaces are not allowed, and the underscore is the only acceptable punctuation mark. Here are some permissible variable names:

zero
relationalOperator
Top10SolidGold
A_good_name_is_better_than_precious_ointment

Most Smalltalk programmers begin local variable names with lowercase letters and global variable names with uppercase letters. When a variable name contains several words, Smalltalk programmers usually begin each word with an uppercase letter (sometimes called “camelcase”). You are free to ignore either of these conventions, but remember that Smalltalk is case-sensitive. The following are all different names to Smalltalk:

VariableName
variableName
variablename

Variable names can contain up to 1024 characters.

Declaring Temporary Variables

GemStone Smalltalk requires you to declare new variable names (implicitly or explicitly) before using them. The simplest kind of variable to declare, and one of the most useful in your initial exploration of GemStone, is the temporary variable. Temporary variables are so called because they are defined only for one execution of the set of statements in which they are declared.

To declare a temporary variable, you must surround it with vertical bars as in this example:

| myTempVariable |
myTempVariable := 2.

You can declare at most 253 temporary variables for a set of statements. Once declared, a variable can name objects of any kind.

To store a variable for later use, or to make its scope global, you must put it in one of GemStone’s shared dictionaries that GemStone Smalltalk uses for symbol resolution. For example:

| myTempVariable |
myTempVariable := 2. 
UserGlobals at: #MyPermanentVariable put: myTempVariable.

Subsequent references to MyPermanentVariable return the value 2.

Pseudovariables

You can change the objects to which most variable names refer simply by assigning them new objects. However, five GemStone Smalltalk variables have values that cannot be changed by assignment; they are therefore called pseudovariables. They are:

nil

Refers to an object representing a null value. Variables not assigned another value automatically refer to nil. nil is an instance of UndefinedObject.

true

Refers to the object representing logical truth. true is an instance of Boolean.

false

Refers to the object representing logical false. false is an instance of Boolean.

self

Refers to the receiver of the message, which differs according to the context. self may be used anywhere a method argument or method temporary would be used, except self is not allowed on the left side of an assignment. When self is used in code that is not part of a method, it resolves to nil.

super

Refers to the receiver of the message, but the search for the method to execute will start in the superclass of the class in which the sending method was compiled. super may only be used as the receiver of a message send, in code within a method.

Assignment

Assignment statements in Smalltalk look like assignment statements in many other languages. The following statement assigns the value 2 to the variable MightySmallInteger:

MightySmallInteger := 2.

The next statement assigns the same String to two different variables (C programmers may notice the similarity to C assignment syntax):

nonmodularity := interdependence := 'No man is an island'.

Message Expressions

Smalltalk objects communicate with one another by means of messages. Most of your effort in Smalltalk programming will be spent in writing expressions in which messages are passed between objects. This subsection discusses the syntax of those message expressions.

You have already seen several examples of message expressions:

2 + 2 
5 + 5

In fact, the only GemStone Smalltalk code segments you have seen that are not message expressions are literals, variables, and simple assignments:

2                           "a literal"
variableName                "a variable"
MightySmallInteger := 2.    "an assignment"

The ubiquity of message-passing is one of the hallmarks of object-oriented programming.

Messages

A message expression consists of:

  • an identifier or expression representing the object to receive the message,
  • one or more identifiers called selectors that specify the message to be sent, and
  • (possibly) one or more arguments that pass information with the message (these are analogous to procedure or function arguments in conventional programming). Arguments can be written as message expressions.

Reserved and Optimized Selectors

GemStone represents selectors internally as symbols, and almost all symbols that confirm to the unary, binary, or keyword selector patterns are acceptable as a selectors. For details on legal selectors, see the BNF here.

There are a few selectors that have been reserved for the sole use of the GemStone kernel classes. The compiler will not allow you to compile methods with reserved selectors.

Those selectors are reserved:

__inProtectedMode 	_and: 	_downTo:by:do: 
_downTo:do: 	_gsReturnNothingEnableEvents 
_gsReturnNoResult 	_isArray 	_isExceptionClass 
_isExecBlock 	_isFloat 	_isInteger
_isNumber 	_isOneByteString 	_isRange 
_isRegexp 	_isRubyHash	_isScaledDecimal 
_isSmallInteger 	_isSymbol 	_leaveProtectedMode 
_or: 	_stringCharSize 	~~ 
and: 	==	ifFalse: 
ifFalse:ifTrue: 	ifNil: 	ifNil:ifNotNil: 
ifNotNil: 	ifNotNil:ifNil:	ifTrue: 
ifTrue:ifFalse:	isKindOf: 	or: 
timesRepeat: 	to:by:do: 	to:do: 
untilFalse 	untilFalse: 	untilTrue 
untilTrue: 	whileFalse 	whileFalse: 
whileTrue 	whileTrue:	repeat

In addition, the following methods are optimized or inlined in the class SmallInteger:

+	-	*	=	~=	<	<=	>	>=

Redefinitions in the class SmallInteger are ignored (or, in some cases, ignored if native code is enabled).

Messages as Expressions

In the following message expression, the object 2 is the receiver, + is the selector, and 8 is the argument:

2 + 8

When 2 sees the selector +, it looks up the selector in its private memory and finds instructions to add the argument (8) to itself and to return the result. In other words, the selector + tells the receiver 2 what to do with the argument 8. The object 2 returns another numeric object 10, which can be stored with an assignment:

myDecimal := 2 + 8.

The selectors that an object understands (that is, the selectors for which instructions are stored in an object’s instruction memory or “method dictionary”) are determined by the object’s class.

Unary Messages

The simplest kind of message consists only of a single identifier called a unary selector. The selector negated, which tells a number to return its negative, is representative:

7 negated
-7

Here are some other unary message expressions:

9 reciprocal.  "returns the reciprocal of 9"
myArray last.  "returns the last element of Array myArray"
DateTime now.  "returns the current date and time"
Binary Messages

Binary message expressions contain a receiver, a single selector consisting of one or two nonalphanumeric characters, and a single argument. You are already familiar with binary message expressions that perform addition. Here are some other binary message expressions (for now, ignore the details and just notice the form):

8 * 8 	"returns 64"
4 < 5 	"returns true"
myObject = yourObject "returns true if myObject and 
	yourObject have the same value"
Keyword Messages

Keyword messages are the most common. Each contains a receiver and up to 15 keyword and argument pairs. In keyword messages, each keyword is a simple identifier ending in a colon.

In the following example, 7 is the receiver, rem: is the keyword selector, and 3 is the argument:

7 rem: 3 "returns the remainder from the division of 7 by 3"

Here is a keyword message expression with two keyword-argument pairs:

| arrayOfStrings |
arrayOfStrings := Array new: 4.
arrayOfStrings at: (2 + 1) put: 'Curly'.
"puts 'Curly' at index position 3 in the receiver"

In a keyword message, the order of the keyword-argument pairs (at:arg1 put:arg2) is significant.

Combining Message Expressions

In a previous example, one message expression was nested within another, and parentheses set off the inner expression to make the order of evaluation clear. It happens that the parentheses were optional in that example. However, in GemStone Smalltalk as in most other languages, you sometimes need parentheses to force the compiler to interpret complex expressions in the order you prefer.

Combinations of unary messages are quite simple; GemStone Smalltalk always groups them from left to right and evaluates them in that order. For example:

9 reciprocal negated

is evaluated as if it were parenthesized like this:

(9 reciprocal) negated

That is, the numeric object returned by 9 reciprocal is sent the message negated.

Binary messages are also invariably grouped from left to right. For example, GemStone Smalltalk evaluates:

2 + 3 * 2

as if the expression were parenthesized like this:

(2 + 3) * 2

This expression returns 10. It may be read: “Take the result of sending + 3 to 2, and send that object the message * 2.”

All binary selectors have the same precedence. Only the sequence of a string of binary selectors determines their order of evaluation; the identity of the selectors doesn’t matter.

However, when you combine unary messages with binary messages, the unary messages take precedence. Consider the following expression, which contains the binary selector + and the unary selector negated:

2 + 2 negated
0

This expression returns the result 0 because the expression 2 negated executes before the binary message expression 2 + 2. To get the result you may have expected here, you would need to parenthesize the binary expression like this:

(2 + 2) negated
-4

Finally, binary messages take precedence over keyword messages. For example:

myArrayOfNums at: 2 * 2

would be interpreted as a reference to myArrayofNums at position 4. To multiply the number at the second position in myArrayOfNums by 2, you would need to use parentheses like this:

(myArrayOfNums at: 2) * 2

Summary of Precedence Rules

1. Parenthetical expressions are always evaluated first.

2. Unary expressions group left to right, and they are evaluated before binary and keyword expressions.

3. Binary expressions group from left to right, as well, and take precedence over keyword expressions.

4. GemStone Smalltalk executes assignments after message expressions.

Cascaded Messages

You will often want to send a series of messages to the same object. By cascading the messages, you can avoid having to repeat the name of the receiver for each message. A cascaded message expression consists of the name of the receiver, a message, a semicolon, and any number of subsequent messages separated by semicolons.

For example:

| arrayOfPoets |
arrayOfPoets := Array new.
(arrayOfPoets add: 'cummings'; add: 'Byron'; add: 'Rimbaud';
yourself)

is a cascaded message expression that is equivalent to this series of statements:

| arrayOfPoets |
arrayOfPoets := Array new.
arrayOfPoets add: 'cummings'.
arrayOfPoets add: 'Byron'.
arrayOfPoets add: 'Rimbaud'.
arrayOfPoets

You can cascade any sequence of messages to an object. And, as always, you are free to replace the receiver’s name with an expression whose value is the receiver.

Array Constructors

Most of the syntax described in this chapter so far is standard Smalltalk syntax. However, GemStone Smalltalk also includes a syntactic construct called a Array constructor. An Array constructor is similar to a literal array, but its elements can be written as nonliteral expressions as well as literals. GemStone Smalltalk evaluates the expressions in an Array constructor at run time.

Array constructors look a lot like literal Arrays; the differences are that array constructors are enclosed in braces and have their elements delimited by periods.

The following example shows an Array constructor whose last element, represented by a message expression, has the value 4.

"An Array constructor"
{'string one' . #SymbolOne . $c . 2+2}

NOTE
The Array constructor is not part of the Smalltalk standard. You should avoid its use in any code that might be ported to an other Smalltalk dialect. Instead, use a message send constructor such as Array class >> #with:, such as
Array with: 'string one' with: $c with: 2+2.

Because any valid GemStone Smalltalk expression is acceptable as an array constructor element, you are free to use variable names as well as literals and message expressions:

| aString aSymbol aCharacter aNumber |
aString := 'string one'.
aSymbol := #symbolOne.
aCharacter := $c.
aNumber := 4.
{aString . aSymbol . aCharacter . aNumber}

The differences in the behavior of array constructors versus literal arrays can be subtle. For example, the literal array:

#(123 huh 456)

is interpreted as an array of three elements: a SmallInteger, aSymbol, and another SmallInteger. This is true even if you declare the value of huh to be a SmallInteger such as 88, as shown in this example:

| huh |
huh := 88.
#( 123 huh 456 )
[20176897 sz:3 cls: 66817 Array] an Array
  #1 [986 sz:0 cls: 74241 SmallInteger] 123 == 0x7b
  #2 [27086593 sz:3 cls: 110849 Symbol] huh
  #3 [3650 sz:0 cls: 74241 SmallInteger] 456 == 0x1c8

The same declaration used in an array constructor, however, produces an array of three SmallIntegers:

| huh |
huh := 88.
{ 123 . huh . 456 }
[20192001 sz:3 cls: 66817 Array] an Array
  #1 [986 sz:0 cls: 74241 SmallInteger] 123 == 0x7b
  #2 [706 sz:0 cls: 74241 SmallInteger] 88 == 0x58
  #3 [3650 sz:0 cls: 74241 SmallInteger] 456 == 0x1c8

Path Expressions

With the exception of Array constructors, most of the syntax described in this chapter so far is standard Smalltalk syntax. GemStone Smalltalk also includes a syntactic construct called a path. A path is a special kind of expression that returns the value of an instance variable.

A path is an expression that contains the names of one or more instance variables separated by periods; a path returns the value of the last instance variable in the series. The sequence of the names reflects the order of the objects’ nesting; the outermost object appears first in a path, and the innermost object appears last. The following path points to the instance variable name, which is contained in the object anEmployee:

anEmployee.name

The path in this example returns the value of instance variable name within anEmployee.

If the instance variable name contained another instance variable called last, the following expression would return the value of last:

anEmployee.name.last

NOTE
Use paths only for their intended purposes. Although you can use a path anywhere an expression is acceptable in a GemStone Smalltalk program, paths are intended for specifying indexes, formulating queries, and sorting. In other contexts, a path returns its value less efficiently than an equivalent message expression. Paths also violate the encapsulation that is one of the strengths of the object-oriented data model. Using them can circumvent the designer’s intention. Finally, paths are not standard Smalltalk syntax. Therefore, programs using them are less portable than other GemStone Smalltalk programs.

Returning Values

Previous discussions have spoken of the “value of an expression” or the “object returned by an expression.” Whenever a message is sent, the receiver of the message returns an object. You can think of this object as the message expression’s value, just as you think of the value computed by a mathematical function as the function’s value.

You can use an assignment statement to capture a returned object:

| myVariable |
myVariable := 8 + 9.    "assign 17 to myVariable" 
myVariable              "return the value of myVariable"
17

You can also use the returned object immediately in a surrounding expression:

"puts 'Moe' at position 2 in arrayOfStrings"
| arrayOfStrings |
arrayOfStrings := Array new: 4.
(arrayOfStrings at: 1+1 put: 'Moe'; yourself) at: 2

And if the message simply adds to a data structure or performs some other operation where no feedback is necessary, you may simply ignore the returned value.

A.3 Blocks

A GemStone Smalltalk block is an object that contains a sequence of instructions. The sequence of instructions encapsulated by a block can be stored for later use, and executed by simply sending the block the unary message value. Blocks find wide use in GemStone Smalltalk, especially in building control structures.

A literal block is delimited by brackets and contains one or more GemStone Smalltalk expressions separated by periods. Here is a simple block:

[3.2 rounded]

To execute this block, send it the message value.

[3.2 rounded] value
3

When a block receives the message value, it executes the instructions it contains and returns the value of the last expression in the sequence. The block in the following example performs all of the indicated computations and returns 8, the value of the last expression.

[89*5. 3+4. 48/6] value
8

You can store a block in a simple variable:

| myBlock |
myBlock := [3.2 rounded].
myBlock value.
3

or store several blocks in more complex data structures, such as Arrays:

| factorialArray |
factorialArray := Array new.
factorialArray at: 1 put: [1];
		at: 2 put: [2 * 1];
		at: 3 put: [3 * 2 * 1];
		at: 4 put: [4 * 3 * 2 * 1].
(factorialArray at: 3) value
6

Because a block’s value is an ordinary object, you can send messages to the value returned by a block.

| myBlock |
myBlock := [4 * 8].
myBlock value / 8
4

The value of an empty block is nil.

[ ] value
nil

Blocks are especially important in building control structures. The following section discusses using blocks in conditional execution.

Blocks with Arguments

You can build blocks that take arguments. To do so, precede each argument name with a colon, insert it at the beginning of the block, and append a vertical bar to separate the arguments from the rest of the block.

Here is a block that takes an argument named myArg:

[ :myArg | 10 + myArg]

To execute a block that takes an argument, send it value: anArgument. For example:

| myBlock |
myBlock := [ :myArg | 10 + myArg]. 
myBlock value: 10.
20

The following example creates and executes a block that takes two arguments. Notice the use of the two-keyword message value:value:.

| divider |
divider := [:arg1 :arg2 | arg1 / arg2]. 
divider value: 4 value: 2
2

A block assigns actual parameter values to block variables in the order implied by their positions. In this example, arg1 takes the value 4 and arg2 takes the value 2.

Variables used as block arguments are known only within their blocks; that is, a block variable is local to its block. A block variable’s value is managed independently of the values of any similarly named instance variables, and GemStone Smalltalk discards it after the block finishes execution. This example illustrates this:

| aVariable |
aVariable := 1. 
[:aVariable | aVariable ] value: 10. 
aVariable
1

You cannot assign to a block variable within its block. This code, for example, would elicit a compiler error:

"The following expression attempts an invalid assignment
to a block variable."
[:blockVar | blockVar := blockVar * 2] value: 10

Blocks and Conditional Execution

Most computer languages, GemStone Smalltalk included, execute program instructions sequentially unless you include special flow-of-control statements. These statements specify that some instructions are to be executed out of order; they enable you to skip some instructions or to repeat a block of instructions. Flow of control statements are usually conditional; they execute the target instructions if, until, or while some condition is met.

GemStone Smalltalk flow of control statements rely on blocks because blocks so conveniently encapsulate sequences of instructions. GemStone Smalltalk’s most important flow of control structures are message expressions that execute a block if or while some object or expression is true or false. GemStone Smalltalk also provides a control structure that executes a block a specified number of times.

Conditional Selection

You will often want GemStone Smalltalk to execute a block of code only if some condition is true or only if it is false. GemStone Smalltalk provides the messages ifTrue: aBlock and ifFalse: aBlock for that purpose. This example contains both of these messages:

5 = 5 ifTrue: ['yes, five is equal to five'].
yes, five is equal to five
 
5 > 10 ifFalse: ['no, five is not greater than ten'].
no, five is not greater than ten

In the first of these examples, GemStone Smalltalk initially evaluates the expression (5 = 5). That expression returns the value true (a Boolean), to which GemStone Smalltalk then sends the selector ifTrue:. The receiver (true) looks at itself to verify that it is, indeed, the object true. Because it is, it proceeds to execute the block passed as an argument to ifTrue:, and the result is a String.

The receiver of ifTrue: or ifFalse: must be Boolean; that is, it must be either true or false. In the above example, the expressions (5 = 5) and (5 > 10) returned true and false, respectively, because GemStone Smalltalk numbers know how to compute and return those values when they receive messages such as = and >.

Two-Way Conditional Selection

You will often want to direct your program to take one course of action if a condition is met and a different course if it isn’t. You could arrange this by sending ifTrue: and then ifFalse: in sequence to a Boolean (true or false) expression. For example:

2 < 5 ifTrue: ['two is less than five'].
two is less than five
 
2 < 5 ifFalse: ['two is not less than five'].
nil

However, GemStone Smalltalk lets you express the same instructions more compactly by sending the single message ifTrue: block1 ifFalse: block2 to an expression or object that has a Boolean value. Which of that message’s arguments GemStone Smalltalk executes depends upon whether the receiver is true or false. In this example, the receiver is true:

2 < 5 ifTrue: ['two is less than five']
ifFalse: ['two is not less than five'].
two is less than five

Conditional Repetition

You will also sometimes want to execute a block of instructions repeatedly as long as some condition is true, or as long as it is false. The messages whileTrue: aBlock and whileFalse: aBlock give you that ability. Any block that has a Boolean value responds to these messages by executing aBlock repeatedly while it (the receiver) is true (whileTrue:) or false (whileFalse:).

Here is an example that repeatedly adds 1 to a variable until the variable equals 5:

| sum |
sum := 0.
[sum = 5] whileFalse: [sum := sum + 1].
sum
5

The next example calculates the total payroll of a miserly but egalitarian company that pays each employee the same salary.

| totalPayroll numEmployees salariesAdded standardSalary |
totalPayroll := 0.00.
salariesAdded := 0.
numEmployees := 40.
standardSalary := 5000.00.
[salariesAdded < numEmployees] whileTrue:
	[totalPayroll := totalPayroll + standardSalary.
	salariesAdded := salariesAdded + 1].
totalPayroll
200000.0

Blocks also accept two unary conditional repetition messages, untilTrue and untilFalse. These messages cause a block to execute repeatedly until the block’s last statement returns either true (untilTrue) or false (untilFalse).

The following example uses untilTrue (rather than whileFalse:).

| sum |
sum := 0.
[sum := sum + 1. sum = 5] untilTrue.
sum
%
5

When GemStone Smalltalk executes the block initially (by sending it the message value), the block’s first statement adds one to the variable sum. The block’s second statement asks whether sum is equal to 5; since it isn’t, that statement returns false, and GemStone Smalltalk executes the block again. GemStone Smalltalk continues to reevaluate the block as long as the last statement returns false (that is, while sum is not equal to 5).

The descriptions of classes Boolean and Block in the image describe these flow of control messages and others.

Formatting Code

GemStone Smalltalk is a free-format language. A space, tab, line feed, form feed, or carriage return affects the meaning of a GemStone Smalltalk expression only when it separates two characters that, if adjacent to one another, would form part of a meaningful token.

In general, you are free to use whatever spacing makes your programs most readable. The following are all equivalent:

 
{'string one'.2+2.'string three'.$c.9*arglebargle}
 
{ 'string one' . 2+2 . 'string three' . $c . 9*arglebargle }
 
{ 'string one'.
   2 + 2.
   'string three'.
   $c.
   9 * arglebargle }
 

A.4 GemStone Smalltalk BNF

This section provides a complete BNF description of GemStone Smalltalk. Here are a few notes about interpreting the grammar:

A = expr

This defines the syntactic production ‘A’ in terms of the expression on the right side of the equals sign.

B = C | D

The vertical bar ‘|’ defines alternatives. In this case, the production “B” is one of either “C” or “D”.

C = '<'

A symbol in accents is a literal symbol.

D = F G

A sequence of two or more productions means the productions in the order of their appearance.

E = [ A ]

Brackets indicate zero or one optional productions.

F = { B }

Braces indicate zero or more occurrences of the productions contained within.

G = A | (B|C)

Parentheses can be used to remove ambiguity.

In the GemStone Smalltalk syntactic productions in Figure A.1, white space is allowed between tokens. White space is required before and after the ‘_’ character.

Figure A.1 GemStone Smalltalk BNF
ArrayBuilder = '#[' [ AExpression { ',' AExpression } ] ']'
	(exists only if System configurationAt:#GemConvertArrayBuilder is true)
ByteArrayLiteral = '#' '[' [ Number { Number } ] ']'
	(exists only if System configurationAt:#GemConvertArrayBuilder is false)
Assignment = VariableName ':=' Statement
AExpression = Primary [ AMessage { ';' ACascadeMessage } ]
ABinaryMessage = [ EnvSpecifier | RubyEnvSpecifier ] ABinarySelector
	Primary [ UnaryMessages ]
ABinaryMessages = ABinaryMessage { ABinaryMessage }
ACascadeMessage = UnaryMessage | ABinaryMessage | AKeyWordMessage
AKeyWordMessage = [ EnvSpecifier | RubyEnvSpecifier  ] AKeyWordPart 
	{ AKeyWordPart }
AKeyWordPart = KeyWord Primary UnaryMessages { ABinaryMessage }
AMessage = [UnaryMessages] [ABinaryMessages] [AKeywordMessage]
Array = '(' { ArrayItem } ')'
ArrayLiteral = '#' Array
CurlyArrayBuilder = '{' [ AExpression { '.' AExpression } ] '}'
ArrayItem = Number | SymbolArrayItem | SymbolLiteral | StringLiteral |
	CharacterLiteral | Array | ArrayLiteral
SymbolArrayItem = Identifier | ( Keyword { Keyword } )
BinaryMessage = [ EnvSpecifier | RubyEnvSpecifier ] BinarySelector Primary 
	[ UnaryMessages ]
BinaryMessages = BinaryMessage { BinaryMessage }
BinaryPattern = BinarySelector VariableName
Block = '[' [ BlockParameters ] [ Temporaries ] Statements ']'
BlockParameters = { Parameter } '|'
CascadeMessage = UnaryMessage | BinaryMessage | KeyWordMessage
Expression = Primary [ Message { ';' CascadeMessage } ]
KeyWordMessage = [ EnvSpecifier | RubyEnvSpecifier ] 
	KeyWordPart { KeyWordPart }
KeyWordPart = KeyWord Primary UnaryMessages { BinaryMessage }
KeyWordPattern = KeyWord VariableName {KeyWord VariableName}
Literal = Number | NegNumber | StringLiteral | CharacterLiteral |
	SymbolLiteral | ArrayLiteral | SpecialLiteral
Message = [UnaryMessages] [BinaryMessages] [KeyWordMessage]
MessagePattern = UnaryPattern | BinaryPattern | KeyWordPattern
Method = MessagePattern [ Primitive ] MethodBody
MethodBody = [ Pragmas ] [ Temporaries ] [ Statements ]
NegNumber = '-' Number
Operand = Path | Literal | Identifier
Operator = '=' | '==' | '<' | '>' | '<=' | '>=' | '~=' | '~~'
ParenStatement = '(' Statement ')'
Predicate = ( AnyTerm | ParenTerm ) { '&' Term }
Primary = ArrayBuilder | CurlyArrayBuilder | Literal | Path | Block |
	SelectionBlock | ParenStatement | VariableName 
Primitive = '<' [ 'protected' | 'unprotected' ] [ 'primitive:' Digits ] '>'
Pragmas =   Pragma [ Pragma ]
Pragma = '< PragmaBody '>'
PragmaBody =  UnaryPragma | KeywordPragma
UnaryPragma  = SpecialLiteral | UnaryPragmaIdentifier
KeywordPragma = PragmaPair [ PragmaPair ]
PragmaPair =  [ KeywordNotPrimitive | BinarySelector ] PragmaLiteral
	KeywordNotPrimitive  is any  Keyword  other than  'primitive:'
UnaryPragmaIdentifier is any  Identifier  except 'protected', unprotected',
	'requiresVc'
PragmaLiteral = Number | NegNumber | StringLiteral | CharacterLiteral |
	SymbolLiteral | SpecialLiteral
SelectionBlock = '{' Parameter } '|' Predicate '}'
Statement = Assignment | Expression
Statements = { [ Pragmas] { Statement '.' } } [ Pragmas] [ ['^'] 
	Statement ['.' [ Pragmas] ]] 
Temporaries = '|' { VariableName } '|'
ParenTerm = '(' AnyTerm ')'
Term = ParenTerm | Operand
AnyTerm = Operand [ Operator Operand ]
UnaryMessage = [ EnvSpecifier | RubyEnvSpecifier ] Identifier
UnaryMessages = { UnaryMessage }
UnaryPattern = Identifier
 

GemStone Smalltalk lexical tokens are shown in Figure A.2. No white space is allowed within lexical tokens.

Figure A.2 GemStone Smalltalk Lexical Tokens
ABinarySelector = any BinarySelector except comma
BinaryExponent = ( 'e' | 'E' | 'd' | 'D' | 'q' ) ['-'] Digits
BinarySelector =  SelectorCharacter [SelectorCharacter]
Character = Any Ascii character with ordinal value 0..255
CharacterLiteral = '$' Character
Comment = '"' { Character } '"'
DecimalExponent = ( 'f' | 'F' ) ['-'] Digits
Digit = '0' | '1' | '2' | ... | '9'
Digits = Digit {Digit}
EndOfSource = the end of the method source string
Exponent = BinaryExponent | DecimalExponent | ScaledDecimalExponent |
	FixedPointExponent
FractionalPart = '.' Digits [Exponent]
FixedPointExponent =  'p' [ ['-'] Digits ] 
Identifier =  SingleLetterIdentifier | MultiLetterIdentifier 
KeyWord = Identifier ':'
Letter = 'A' | 'B' | ... | 'Z' | 'a' | 'b' | ... | 'z' | '_'
MultiLetterIdentifier = Letter ( Letter | Digit ) { Letter | Digit }
Number = RadixedLiteral | NumericLiteral
Numeric = Digit | 'A' | 'B' | ... | 'Z'
NumericLiteral = Digits ( [FractionalPart] | [Exponent] )
Numerics = Numeric { Numeric }
Parameter = ':' VariableName
	(white space allowed between : and variableName)
Path = Identifier '.' PathIdentifier { '.' PathIdentifier }
PathIdentifier  =  Identifier |  '*'
EnvSpecifier = '@env' Digits ':'    
	(no white space before or after Digits)
RubyEnvSpecifier '@ruby' Digits ':'
	(other keyword tokens allowed after RubyEnvSpecifier)
RadixedLiteral = Digits ( '#' | 'r' ) ['-'] Numerics
ScaledDecimalExponent =  's' [ ['-'] Digits ]
ScdExponTerminator = '"' | WhiteSpace | ',' | ')' | ']' | '}' | '.' | 
	';' | 	EndOfSource
SelectorCharacter = '+' | '-' | '\' | '*' | '~' | '<' | '>' | '=' 
	| '|' | '/' | '&' | '@' | '%' | ',' | '?' | '!' 
SingleLetter 'A' | 'B' | ... | 'Z' | 'a' | 'b' | ... | 'z' 
SingleLetterIdentifier =  SingleLetter
SpecialLiteral = 'true' | 'false' | 'nil' | '_remoteNil' 
StringLiteral = "'" { Character | "''" } "'"
Symbol = Identifier | BinarySelector | ( Keyword { Keyword } )
SymbolLiteral = '#' ( Symbol | StringLiteral )
VariableName = Identifier
 
 

 

Previous chapter