Smalltalk80LanguageImplementation:Chapter 02: Difference between revisions

From 흡혈양파의 번역工房
Jump to navigation Jump to search
(오타수정)
(정오표 수정)
 
Line 187: Line 187:
initialIndex
initialIndex
textEditor
textEditor
bin1`4
bin14
bin14Total
bin14Total
HouseholdFinances
HouseholdFinances
Line 204: Line 204:
===Assignments===
===Assignments===


A literal constant will always refer to the same object, but a variable name may refer to different objects at different times. The object referred to by a variable is changed when an assignment expression is evaluated. Assignments were not listed earlier as a type of expression since any expression can become an assignment by including an assign ment prefix.
A literal constant will always refer to the same object, but a variable name may refer to different objects at different times. The object referred to by a variable is changed when an assignment expression is evaluated. Assignments were not listed earlier as a type of expression since any expression can become an assignment by including an assignment prefix.




Line 229: Line 229:




More than one assignment prefix can be included, indicating that the values of serveral variables are changed.
More than one assignment prefix can be included, indicating that the values of several variables are changed.


<syntaxhighlight lang="smalltalk">
<syntaxhighlight lang="smalltalk">
Line 246: Line 246:
{| style="border: 1px solid black;"
{| style="border: 1px solid black;"
|- style="vertical-align:top;"
|- style="vertical-align:top;"
|nil||refers to an object used as thevalue of a variable when no other object is appropriate . Variables that have not been otherwise initialized refer to nil.
|nil||refers to an object used as the value of a variable when no other object is appropriate . Variables that have not been otherwise initialized refer to nil.
|- style="vertical-align:top;"
|- style="vertical-align:top;"
|true||refers to an object that represents logical accuracy. It is used as an affirmative response to a message making a simple yes-no inquiry.
|true||refers to an object that represents logical accuracy. It is used as an affirmative response to a message making a simple yes-no inquiry.
Line 318: Line 318:
{| style="border: 1px solid black;"
{| style="border: 1px solid black;"
|- style="vertical-align:top;"
|- style="vertical-align:top;"
|HousehoidFinances spend: 32.50 on: 'utilities'||informs the financial history named HouseholdFinances that $32.50 has been spent on utility bills.
|HouseholdFinances spend: 32.50 on: 'utilities'||informs the financial history named HouseholdFinances that $32.50 has been spent on utility bills.
|- style="vertical-align:top;"
|- style="vertical-align:top;"
|HouseholdFinances totalSpentFor: 'food'||asks HouseholdFinances how much money has been spent for food.
|HouseholdFinances totalSpentFor: 'food'||asks HouseholdFinances how much money has been spent for food.
Line 330: Line 330:




A message's selector is aname for the type of interaction the sender desires with the receiver. For example, in the message
A message's selector is a name for the type of interaction the sender desires with the receiver. For example, in the message


<syntaxhighlight lang="smalltalk">
<syntaxhighlight lang="smalltalk">
Line 354: Line 354:




the selectors are+ . Both messages ask the receiver to calculate and return a sum. These messages each contain an object in addition to the selector (4 in the first expression and increment in the second). The additional objects in the message are arguments that specify the amount to be added.
the selectors are +. Both messages ask the receiver to calculate and return a sum. These messages each contain an object in addition to the selector (4 in the first expression and increment in the second). The additional objects in the message are arguments that specify the amount to be added.




The following two message expressions describe the same kind of operation. The receiver is an instance of FinancialHistory and will return the amount of money spent for aparticular reason. The argument indicates the reason of interest. The first expression requests the amount spent for utility bills.
The following two message expressions describe the same kind of operation. The receiver is an instance of FinancialHistory and will return the amount of money spent for a particular reason. The argument indicates the reason of interest. The first expression requests the amount spent for utility bills.


<syntaxhighlight lang="smalltalk">
<syntaxhighlight lang="smalltalk">
Line 565: Line 565:
# Binary expressions take precedence over keyword expressions.
# Binary expressions take precedence over keyword expressions.
# Unary expressions take precedence over binary expressions.
# Unary expressions take precedence over binary expressions.
# Parenthesized expressions take precendence over unary expressions.
# Parenthesized expressions take precedence over unary expressions.




Line 636: Line 636:




When a block expression is encountered, the statements enclosed in the brackets are not executed immediately. The value of a block expression is an object t hat can execute these enclosed expressions at a later time, when requested to do so. For example, the expression
When a block expression is encountered, the statements enclosed in the brackets are not executed immediately. The value of a block expression is an object that can execute these enclosed expressions at a later time, when requested to do so. For example, the expression


<syntaxhighlight lang="smalltalk">
<syntaxhighlight lang="smalltalk">
actions at: 'monthly payments'
actions at: 'monthly payments'
put: [HouseholdFinances spend: 650 on: 'rent'.
put: [HouseholdFinances spend: 650 on: 'rent'.
HousehoidFinances spend: 7.25 on: 'newspaper'.
HouseholdFinances spend: 7.25 on: 'newspaper'.
HouseholdFinances spend: 225.50 on: 'car payment']
HouseholdFinances spend: 225.50 on: 'car payment']
</syntaxhighlight>
</syntaxhighlight>

Latest revision as of 08:58, 9 May 2014

Chapter 2 Expression Syntax

Expression Syntax

Chapter 1 introduced the fundamental concepts of the Smalltalk-80 system. System components are represented by objects. Objects are instances of classes. Objects interact by sending messages. Messages cause methods to be executed. This chapter introduces an expression syntax for describing objects and messages. The next chapter introduces a syntax for describing classes and methods.


An expression is a sequence of characters that describes an object called the value of the expression. The syntax presented in this chapter explains which sequences of characters form legal expressions. There are four types of expression in the Smalltalk-80 programming language.

  1. Literals describe certain constant objects, such as numbers and character strings.
  2. Variable names describe the accessible variables. The value of a variable name is the current value of the variable with that name.
  3. Message expressions describe messages to receivers. The value of a message expression is determined by the method the message invokes. That method is found in the class of the receiver.
  4. Block expressions describe objects representing deferred activities. Blocks are used to implement control structures.


Expressions are found in two places, in methods and in text displayed on the screen. When a message is sent, a method from the receiver's class is selected and its expressions are evaluated. Part of the user interface allows expressions to be selected on the screen and evaluated. The details of selecting and evaluating expressions on the screen fall outside the scope of this book, since they are part of the user interface. Some examples, however, are given in Chapter 17.


Of the four types of expression listed above, only the variable names are context-dependent. An expression's location in the system determines which character sequences are legal variable names. The set of variable names available in a method's expressions depends on the class in which the method is found. For example, methods in class Rectangle and methods in class Point have access to different sets of variable names. The variables available in a class's methods will be fully described in Chapters 3, 4, and 5. The variable names available for use in expressions on the screen depend on where the expressions are displayed on the screen. All other aspects of the expression syntax are independent of the expression's location.


The syntax for expressions is summarized in the diagram that appears inside the back cover of this book. The rest of this chapter describes the four types of expression.


Literals

Five kinds of objects can be referred to by literal expressions. Since the value of a literal expression is always the same object, these expressions are also called literal constants. The five types of literal constant are:

  1. numbers
  2. individual characters
  3. strings of characters
  4. symbols
  5. arrays of other literal constants


Numbers

Numbers are objects that represent numerical values and respond to messages that compute mathematical results. The literal representation of a number is a sequence of digits that may be preceded by a minus sign and/or followed by a decimal point and another sequence of digits. For example,

3
30.45
-3
0.005
-14.0
13772


Number literals can also be expressed in a nondecimal base by preceding the digits with a radix prefix. The radix prefix includes the value of the digit radix (always expressed in decimal) followed by the letter "r". The following examples specify numbers in octal with their corresponding decimal values.

octal decimal
8r377 255
8r153 107
ir34.1 28.125
8r-37 -31


When the base is greater than ten, the capital letters starting with "A" are used for digits greater than nine. The following examples specify numbers in hexadecimal with their corresponding decimal values.

hexadecimal decimal
16r106 262
16rF 255
16rAC.DC 172.859
16R-1.C -1.75


Number literals can also be expressed in scientific notation by following the digits of the value with an exponent suffix. The exponent suffix includes the letter "e" followed by the exponent (expressed in decimal). The number specified before the exponent suffix is multiplied by the radix raised to the power specified by the exponent.

scientific notation decimal
1.586e5 158600.0
1.586e-3 0.001586
8r3e2 192
2r11e6 192


Characters

Characters are objects that represent the individual symbols of an alphabet. A character literal expression consists of a dollar sign followed by any character, for example,

$a
$M
$-
$$
$1


Strings

Strings are objects that represent sequences of characters. Strings respond to messages that access individual characters, replace substrings, and perform comparisons with other strings. The literal representation of a string is a sequence of characters delimited by single quotes, for example,

'hi'
'food'
'the Smalltalk-80 system'


Any character may be included in a string literal. If a single quote is to be included in a string, it must be duplicated to avoid confusion with the delimiters. For example, the string literal

'can''t'


refers to a string of the five characters $c,$a,$n,$', and $t.


Symbols

Symbols are objects that represent strings used for names in the system. The literal representation of a symbol is a sequence of alphanumeric characters preceded by a pound sign, for example,

#bill
#M63


There will never be two symbols with the same characters; each symbol is unique. This makes it possible to compare symbols efficiently.


Arrays

An array is a simple data structure object whose contents can be referenced by an integer index from one to a number that is the size of the array. Arrays respond to messages requesting access to their contents. The literal representation of an array is a sequence of other literals--numbers, characters, strings, symbols, and arrays--delimited by parentheses and preceded by a pound sign. The other literals are separated by spaces. Embedded symbols and arrays are not preceded by pound signs. An array of three numbers is described by the expression

#(1 2 3)


An array of seven strings is described by the expression

#('food' 'utilities' 'rent' 'household' 'transportation' 'taxes' 'recreation')


An array of two arrays and two numbers is described by the expression

#(('one' 1)('not' 'negative') 0 - 1)


And an array of a number, a string, a character, a symbol, and another array is described by the expression

#(9 'nine' $9 nine (0 'zero' $0 () 'e' $f 'g' $h 'i'))


Variables

The memory available to an object is made up of variables. Most of these variables have names. Each variable remembers a single object and the variable's name can be used as an expression referring to that object. The objects that can be accessed from a particular place are determined by which variable names are available. For example, the contents of an object's instance variables are unavailable to other objects because the names of those variables can be used only in the methods of the object's class.


A variable name is a simple identifier, a sequence of letters and digits beginning with a letter. Some examples of variable names are:

index
initialIndex
textEditor
bin14
bin14Total
HouseholdFinances
Rectangle
IncomeReasons


There are two kinds of variables in the system, distinguished by how widely they are accessible. Private variables are accessible only to a single object. Instance variables are private. Shared variables can be accessed by more than one object. Private variable names are required to have lowercase initial letters; shared variable names are required to have uppercase initial letters. The first five example identifiers shown above refer to private variables and the last three refer to shared variables.


Another capitalization convention evident in the examples above is that identifiers formed by concatenating several words capitalize each word following the first one. This convention is not enforced by the system.


Assignments

A literal constant will always refer to the same object, but a variable name may refer to different objects at different times. The object referred to by a variable is changed when an assignment expression is evaluated. Assignments were not listed earlier as a type of expression since any expression can become an assignment by including an assignment prefix.


An assignment prefix is composed of the name of the variable whose value will be changed followed by a left arrow (← ). The following example is a literal expression that has an assignment prefix. It indicates that the variable named quantity should now refer to the object representing the number 19.

quantity   19


The following example is a variable-name expression with an assignment prefix. It indicates that the variable named index should refer to the same object as does the variable named initialIndex.

index   initialIndex


Other examples of assignment expressions are:

chapterName   'Expression Syntax'
flavors   #('vanilla' 'chocolate' 'butter pecan' 'garlic')


More than one assignment prefix can be included, indicating that the values of several variables are changed.

index   initialIndex   1


This expression indicates that both the variables named index and initialIndex should refer to the number 1. Message expressions and block expressions can also have assignment prefixes, as will be seen in the following sections.


Pseudo-variable Names

A pseudo-variable name is an identifier that refers to an object. In this way, it is similar to a variable name. A pseudo-variable name is different from a variable name in that its value cannot be changed with an assignment expression. Some of the pseudo-variables in the system are constants; they always refer to the same objects. Three important pseudo-variable names are nil, true, and false.

nil refers to an object used as the value of a variable when no other object is appropriate . Variables that have not been otherwise initialized refer to nil.
true refers to an object that represents logical accuracy. It is used as an affirmative response to a message making a simple yes-no inquiry.
false refers to an object that represents logical inaccuracy. It is used as a negative response to a message marking a simple yes-no inquiry.


The objects named true and false are called Boolean objects. They represent the answers to yes-no questions. For example, a number will respond with true or false to a message asking whether or not the number is greater than another number. Boolean objects respond to messages that compute logical functions and perform conditional control structures.


There are other pseudo-variables in the system (for example, self and super) whose values are different depending on where they are used. These will be described in the next three chapters.


Messages

Messages represent the interactions between the components of the Smalltalk-80 system. A message requests an operation on the part of the receiver. Some examples of message expressions and the interactions they represent follow.


Messages to numbers representing arithmetic operations

3 + 4 computes the sum of three and four.
index + 1 adds one to the number named index.
index > limit inquires whether or not the number named index is greater than the number named limit.
theta sin computes the sine of the number named theta.
quantity sqrt computes the positive square root of the number named quantity.


Messages to linear data structures representing the addition or removal of information

list addFirst: newComponent adds the object named newComponent as the first element of the linear data structure named list.
list removeLast removes and returns the last element in list.


Messages to associative data structures (such as dictionaries) representing the addition or removal of information

ages at:'Brett Jorgensen' put: 3 associates the string 'Brett Jorgensen' with the number 3 in the dictionary named ages.
addresses at:'Peggy Jorgensen' looks up the object associated with the string 'Peggy Jorgensen' in the dictionary named addresses.


Messages to rectangles representing graphical inquiries and calculations

frame center answers the position of the center of the rectangle named frame.
frame containsPoint: cursorLocation answers true if the position named cursorLocation is inside the rectangle named frame, and false otherwise.
frame intersect: clippingBox computes the rectangle that represents the intersection of the two rectangles named frame and clippingBox.


Messages to financial history records representing transactions and inquiries

HouseholdFinances spend: 32.50 on: 'utilities' informs the financial history named HouseholdFinances that $32.50 has been spent on utility bills.
HouseholdFinances totalSpentFor: 'food' asks HouseholdFinances how much money has been spent for food.


Selectors and Arguments

A message expression describes a receiver, selector, and possibly some arguments. The receiver and arguments are described by other expressions. The selector is specified literally.


A message's selector is a name for the type of interaction the sender desires with the receiver. For example, in the message

theta sin


the receiver is a number referred to by the variable named theta and the selector is sin. It is up to the receiver to decide how to respond to the message (in this case, how to compute the sine function of its value).


In the two message expressions

3 + 4


and

previousTotal + increment


the selectors are +. Both messages ask the receiver to calculate and return a sum. These messages each contain an object in addition to the selector (4 in the first expression and increment in the second). The additional objects in the message are arguments that specify the amount to be added.


The following two message expressions describe the same kind of operation. The receiver is an instance of FinancialHistory and will return the amount of money spent for a particular reason. The argument indicates the reason of interest. The first expression requests the amount spent for utility bills.

HouseholdFinances totalSpentOn: 'utilities'


The amount spent for food can be found by sending a message with the same selector, but with a different argument .

HouseholdFinances totalSpentOn: 'food'


The selector of a message determines which of the receiver's operations will be invoked. The arguments are other objects that are involved in the selected operation.


❏ Unary Messages Messages without arguments are called unary messages. For example, the money currently available according to HouseholdFinances is the value of the unary message expression

HouseholdFinances cashOnHand


These messages are called unary because only one object, the receiver, is involved. A unary message selector can be any simple identifier. Other examples of unary message expressions are

theta sin
quantity sqrt
nameString size


❏ Keyword Messages The general type of message with one or more arguments is the keyword message. The selector of a keyword message is composed of one or more keywords, one preceding each argument. A keyword is a simple identifier with a trailing colon. Examples of expressions describing single keyword messages are

HouseholdFinances totalSpentOn: 'utilities'
index max: limit


A message with two arguments will have a selector with two keywords. Examples of expressions describing double keyword messages are

HouseholdFinances spend: 30.45 on: 'food'
ages at: 'Brett Jorgensen' put: 3


When the selector of a multiple keyword message is referred to independently, the keywords are concatenated. The selectors of the last two message expressions are spend:on: and at:put:. There can be any number of keywords in a message, but most messages in the system have fewer than three.


❏ Binary Messages There is one other type of message expression that takes a single argument , the binary message. A binary message selector is composed of one or two nonalphanumeric characters. The only restriction is that the second character cannot be a minus sign. Binary selectors tend to be used for arithmetic messages. Examples of binary message expressions are

3 + 4
total - 1
total < = max


Returning Values

Smalltalk-80 messages provide two-way communication. The selector and arguments transmit information to the receiver about what type of response to make. The receiver transmits information back by returning an object that becomes the value of the message expression. If a message expression includes an assignment prefix, the object returned by the receiver will become the new object referred to by the variable. For example, the expression

sum   3 + 4


makes 7 be the new value of the variable named sum. The expression

x   theta sin


makes the sine of theta be the new value of the variable named x. If the value of theta is 1, the new value of x becomes 0.841471. If the value of theta is 1.5, the new value of × becomes 0.997495.


The number referred to by index can be incremented by the expression

index   index + 1


Even if no information needs to be communicated back to the sender, a receiver always returns a value for the message expression. Returning a value indicates that the response to the message is complete. Some messages are meant only to inform the receiver of something. Examples are the messages to record financial transactions described by the following expressions.

HouseholdFinances spend : 32.50 on: 'utilities'
HouseholdFinances receive: 1000 from: 'pay'


The receiver of these messages informs the sender only that it is finished recording the transaction. The default value returned in such cases is usually the receiver itself. So, the expression

var   HouseholdFinances spend: 32.50 on: 'utilities'


results in var referring to the same financial history as HouseholdFinances.


Parsing

All of the message expressions shown thus far have described the receiver and arguments with literals or variable names. When the receiver or argument of a message expression is described by another message expression, the issue of how the expression is parsed arises. An example of a unary message describing the receiver of another unary message is

1.5 tan rounded


Unary messages are parsed left to right. The first message in the example is the unary selector tan sent to 1.5. The value of that message expression (a number around 14.1014) receives the unary message rounded and returns the nearest integer, 14. The number 14 is the value of the whole expression.


Binary messages are also parsed left to right. An example of a binary message describing the receiver of another binary message is

index + offset * 2


The value returned by index from the message + offset is the receiver for the binary message * 2. All binary selectors have the same precedence; only the order in which they are written matters. Note that this makes mathematical expressions in the Smalltalk-80 language different from those in many other languages in which multiplication and division take precedence over addition and subtraction. Parentheses can be used to change the order of evaluation. A message within parentheses is sent before any messages outside the parentheses. If the previous example were written as

index + (offset * 2)


the multiplication would be performed before the addition. Unary messages take precedence over binary messages. If unary messages and binary messages appear together, the unary messages will all be sent first. In the example

frame width + border width * 2


the value of frame width is the receiver of the binary message whose selector is + and whose argument is the value of border width. The value of the + message is, in turn, the receiver of the binary message * 2. The expression parses as if it had been parenthesized as follows:

((frame width) + (border width)) * 2


Parentheses can be used to send binary messages before unary messages. The expression

2 * theta sin


calculates twice the sine of theta, while the expression

(2 * theta) sin


calculates the sine of twice theta.


Whenever keywords appear in an unparenthesized message, they compose a single selector. Because of this concatenation, there is no left-to-right parsing rule for keyword messages. If a keyword message is to be used as a receiver or argument of another keyword message, it must be parenthesized. The expression

frame scale: factor max: 5


describes a single two-argument keyword message whose selector is scale:max:. The expression

frame scale: (factor max: 5)


describes two single keyword messages whose selectors are scale: and max:. The value of the expression factor max: 5 is the argument for the scale: message to frame.


Binary messages take precedence over keyword messages. When unary, binary, and keyword messages appear in the same expression without parentheses, the unaries are sent first, the binaries next, and the keyword last. The example

bigFrame width: smallFrame width * 2


is evaluated as if it had been parenthesized as follows:

bigFrame width: ((smallFrame width) * 2)


In the following example, a unary message describes the receiver of a keyword message and a binary message describes the argument.

OrderedCollection new add: value * rate


To summarize the parsing rules:

  1. Unary expressions parse left to right.
  2. Binary expressions parse left to right.
  3. Binary expressions take precedence over keyword expressions.
  4. Unary expressions take precedence over binary expressions.
  5. Parenthesized expressions take precedence over unary expressions.


Formatting Conventions

A programmer is free to format expressions in various ways using spaces, tabs, and carriage returns. For example, multiple keyword messages are often written with each keyword-argument pair on a different line, as in

ages at: 'Brett Jorgensen'
    put: 3


or

HouseholdFinances
    spend: 30.45
    on: 'food'


The only time that a space, tab, or carriage return affects the meaning of an expression is when its absence would cause two letters or two numbers to fall next to each other.


Cascading

There is one special syntactic form called cascading that specifies multiple messages to the same object. Any sequence of messages can be expressed without cascading. However, cascading often reduces the need for using variables. A cascaded message expression consists of one description of the receiver followed by several messages separated by semicolons. For example,

OrderedCollection new add: 1; add: 2; add:3


Three add: messages are sent to the result of OrderedCollection new. Without cascading, this would have required four expressions and a variable. For example, the following four expressions, separated by periods, have the same result as the cascaded expression above.

temp   OrderedCollection new.
temp add: 1.
temp add: 2.
temp add: 3


Blocks

Blocks are objects used in many of the control structures in the Smalltalk-80 system. A block represents a deferred sequence of actions. A block expression consists of a sequence of expressions separated by periods and delimited by square brackets. For example,

[index   index + 1]


or

[index   index +1.
array at: index put: 0]


If a period follows the last expression, it is ignored, as in

[expenditures at: reason.]


When a block expression is encountered, the statements enclosed in the brackets are not executed immediately. The value of a block expression is an object that can execute these enclosed expressions at a later time, when requested to do so. For example, the expression

actions at: 'monthly payments'
	put: [HouseholdFinances spend: 650 on: 'rent'.
		HouseholdFinances spend: 7.25 on: 'newspaper'.
		HouseholdFinances spend: 225.50 on: 'car payment']


does not actually send any spend:on: messages to HouseholdFinances. It simply associates a block with the string 'monthly payments'. The sequence of actions a block describes will take place when the block receives the unary message value. For example, the following two expressions have identical effects.

index   index + 1


and

[index   index +1] value


The object referred to by the expression

actions at: 'monthly payments'


is the block containing three spend:on: messages. The execution of the expression

(actions at: 'monthly payments') value


results in those three spend:on: messages being sent to HouseholdFinances.


A block can also be assigned to a variable. So if the expression

incrementBlock   [index   index + 1]


is executed, then the expression

incrementBlock value
increments index.


The object returned after a value message is sent to a block is the value of the last expression in the sequence. So if the expression

addBlock   [index + 1]


is executed, then another way to increment index is to evaluate

index   addBlock value


A block that contains no expressions returns nil when sent the message value. The expression

[] value


has the value nil.


Control Structures

A control structure determines the order of some activities. The fundamental control structure in the Smalltalk-80 language provides that a sequence of expressions will be evaluated sequentially. Many nonsequential control structures can be implemented with blocks. These control structures are invoked either by sending a message to a block or by sending a message with one or more blocks as arguments. The response to one of these control structure messages determines the order of activities with the pattern of value messages it sends to the block(s).


Examining the evaluation of the following sequence of expressions gives an example of the way blocks work.

incrementBlock   [index   index + 1].
sumBlock   [sum + (index * index)].
sum   0.
index   1.
sum   sumBlock value.
incrementBlock value.
sum   sumBlock value


The 15 actions taken as a result of evaluating this sequence of expressions are

  1. Assign a block to incrementBlock.
  2. Assign a block to sumBlock.
  3. Assign the number 0 to sum.
  4. Assign the number 1 to index.
  5. Send the message value to the block sumBlock.
  6. Send the message * 1 to the number 1.
  7. Send the message + 1 to the number 0.
  8. Assign the number 1 to sum.
  9. Send the message value to the block incrementBlock.
  10. Send the message + 1 to the number 1.
  11. Assign the number 2 to index.
  12. Send the message value to the block sumBlock.
  13. Send the message * 2 to the number 2.
  14. Send the message + 4 to the number 1.
  15. Assign the number 5 to sum.


An example of a control structure implemented with blocks is simple repetition, represented by a message to an integer with timesRepeat: as the selector and a block as the argument. The integer will respond by sending the block as many value messages as its own value indicates. For example, the following expression doubles the value of the variable named amount four times.

4 timesRepeat: [amount   amount + amount]


Conditionals

Two common control structures implemented with blocks are conditional selection and conditional repetition. Conditional selection is similar to the if-then-else statements in Algol-like languages and conditional repetition is similar to the while and until statements in those languages. These conditional control structures use the two Boolean objects named true and false described in the section on pseudo-variables. Booleans are returned from messages that ask simple yes-no questions (for example, the magnitude comparison messages: <, =, < =, >, > =, ~=).


❏ Conditional Selection The conditional selection of an activity is provided by a message to a Boolean with the selector ifTrue:ifFalse: and two blocks as arguments. The only objects that understand ifTrue:ifFalse: messages are true and false. They have opposite responses: true sends value to the first argument block and ignores the second; false sends value to the second argument block and ignores the first. For example, the following expression assigns 0 or 1 to the variable parity depending on whether or not the value of the variable number is divisible by 2. The binary message \\ computes the modulus or remainder function.

(number \\ 2) = 0
	ifTrue: [parity   0]
	ifFalse: [parity   1]


The value returned from ifTrue:ifFalse is the value of the block that was executed. The previous example could also be written

parity   (number \\ 2) = 0 ifTrue: [0] ifFalse: [1]


In addition to ifTrue:ifFalse:, there are two single-keyword messages that specify only one conditional consequent. The selectors of these messages are ifTrue: and ifFalse:. These messages have the same effect as the ifTrue:ifFalse: message when one argument is an empty block. For example, these two expressions have the same effect.

index < = limit
	ifTrue: [total   total + (list at: index)]


and

index < = limit
	ifTrue: [total   total + (list at: index)]
	ifFalse: []


Since the value of an empty block is nil, the following expression would set lastElement to nil if index is greater than limit.

lastElement   index > limit itFalse: [list at: index]


❏ Conditional Repetition The conditional repetition of an activity is provided by a message to a block with the selector whileTrue: and another block as an argument . The receiver block sends itself the message value and, if the response is true, it sends the other block value and then starts over, sending itself value again. When the receiver's response to value becomes false, it stops the repetition and returns from the whileTrue: message. For example, conditional repetition could be used to initialize all of the elements of an array named list.

index   1.
[index < = list size]
	whileTrue: [list at: index put: 0.
		index   index + 1]


Blocks also understand a message with selector whileFalse: that repeats the execution of the argument block as long as the value of the receiver is false. So, the following expressions are equivalent to the one above.

index   1.
[index > list size]
	whileFalse: [list at: index put: 0.
		index   index + 1]


The programmer is free to choose whichever message makes the intent of the repetition clearest. The value returned by both whileTrue: and whileFalse: is always nil.


Block Arguments

In order to make some nonsequential control structures easy to express, blocks may take one or more arguments. Block arguments are specified by including identifiers preceded by colons at the beginning of a block. The block arguments are separated from the expressions that make up the block by a vertical bar. The following two examples describe blocks with one argument.

[:array | total   total + array size]


and

[:newElement |
    index   index + 1.
    list at: index put: newElement]


A common use of blocks with arguments is to implement functions to be applied to all elements of a data structure. For example, many objects representing different kinds of data structures respond to the message do:, which takes a single-argument block as its argument. The object that receives a do: message evaluates the block once for each of the elements contained in the data structure. Each element is made the value of the block argument for one evaluation of the block. The following example calculates the sum of the squares of the first five primes. The result is the value of sum.

sum   0.
#(2 3 5 7 11) do: [ :prime | sum   sum + (prime * prime)]


The message collect: creates a collection of the values produced by the block when supplied with the elements of the receiver. The value of the following expression is an array of the squares of the first five primes.

#(2 3 5 7 11) collect: [ :prime | prime * prime]


The objects that implement these control structures supply the values of the block arguments by sending the block the message value:. A block with one block argument responds to value: by setting the block argument to the argument of value: and then executing the expressions in the block. For example, evaluating the following expressions results in the variable total having the value 7.

sizeAdder   [ :array | total   total + array size].
total   0.
sizeAdder value: #(a b c).
sizeAdder value: #(1 2).
sizeAdder value: #(e f)


Blocks can take more than one argument. For example

[ :x :y | (x * x) + (y * y)]


or

[ :frame :clippingBox | frame intersect: clippingBox]


A block must have the same number of block arguments as the number of value: keywords in the message to evaluate it. The two blocks above would be evaluated by means of a two-keyword message with selector value:value:. The two arguments of the message specify the values of the two block arguments, in order. If a block receives an evaluation message with a different number of arguments from the number of block arguments it takes, an error will be reported.


Summary of Terminology

The syntax of expressions is summarized inside the back cover of this book.

expression A sequence of characters that describes an object.
literal An expression describing a constant, such as a number or a string.
symbol A string whose sequence of characters is guaranteed to be different from that of any other symbol.
array A data structure whose elements are associated with integer indices.
variable name An expression describing the current value of a variable.
assignment An expression describing a change of a variable's value.
pseudo-variable name An expression similar to a variable name. However, unlike a variable name, the value of a pseudo-variable name cannot be changed by an assignment.
receiver The object to which a message is sent.
message selector The name of the type of operation a message requests of its receiver.
message argument An object that specifies additional information for an operation.
unary message A message without arguments.
keyword An identifier with a trailing colon.
keyword message A message with one or more arguments whose selector is made up of one or more keywords.
binary message A message with one argument whose selector is made up of one or two special characters.
cascading A description of several messages to one object in a single expression.
block A description of a deferred sequence of actions.
block argument A parameter that must be supplied when certain blocks are evaluated.
value A message to a block asking it to carry out the set of actions it represents.
value: A keyword used in a message to a block that has block arguments; the corresponding message asks the block to carry out its set of actions.
ifTrue:if False: Message to a Boolean requesting conditional selection.
if False:if True: Message to a Boolean requesting conditional selection.
ifTrue: Message to a Boolean requesting conditional selection.
if False: Message to a Boolean requesting conditional selection.
whileTrue: Message to a block requesting conditional repetition
whileFalse: Message to a block requesting conditional repetition.
do: A message to a collection requesting enumeration of its elements.
collect: A message to a collection requesting transformation of its elements.


Notes