In the previous chapter, the coding convention and message execution order were discuessed. This chapter concentrates on the Smalltalk grammer or syntax. There are several rules that govern the way Smalltalk statements are written. A Smalltalk statement, in addition to containing messages, may also contain an assignment statement (setting the contents of a variable to specific value), or a return expression.
Recall from the previous chapter that when
Smalltalk processes each message, the statement in the message is replaced
by a return value which is the result of that executing that message. The
following is an example of the method name:address: for the Student
class:
name: aName address: anAddress self name: aName. self address: anAddress
Periods are optional for the last statement in a method. Smalltalk separates executable statements by looking for a period. As a result, multiple statements can appear on one line, or one statement can appear on many lines. The previous example can be written as follows:
name: aName Student: anAddress self name: aName. self address: anAddressTo make the code easier to read, it is wise to have no more than one statement on one line. Blank lines are ingnored by Smalltalk.
The syntax for assigment statement is:
variable := statementwhere variable can be a name within the scope of the method and statement can be any valid Smalltalk statement.
For example:
x := 7. k := `some character'. aVariable := j * k.
For example:
^statementThe result of statement is returned, where statement can be any valid statement.
A return expression normally appears in front of the last statement in a method or in front of a statement that executes as part of a condition statment. This practice is necessary because the return expression ends the execution ot the method in which it is found.
Example 3.1: Returning a value
y := y + 7. ^y "return the value of y"The statement also can be written as:
^y := y + 7. "return the value of y"To return the value of y + 7 without changing value of y:
^y + 7 "return value of y + 7 but does not change value of y"
a < b ifTrue: [^a] ifFalse:[^b]This example contains more than one return statement. This code returns the value of a if a is greater than b, otherwise it returns the value of b. Conditional statements will be discussed in greater detail in a later chapter.
In the statement ^a, the expression is the variable a and the returned value of the expression is the value of a. The value of a statement is always equivalent to the last expression executed in the statement.
For statements that has more than one message, the return value equals the value from the last message executed.
For example:
^Student new name: aPerson name![]()
![]()
(2) the name message is sent to the object pointed to by the variable aPerson
(3) the name: message is sent to the result of the new message.
"this is a comment in Smalltalk"It is an accepted convention to have comments at the beginning of a method to explain its behavior, including its return value.
For example:
name: aName address: adAddress "Set the receiver's name and address to the specified values." self name: aName. self address: anAddress name "Return the student name for the receiver." ^nameSmalltalk ignores all comments when scanning a method for execution. This means that a comment can appead anyway as long as it is placed within two double quatations. Placing a period at the end of a comment causes Smalltalk to associate that period with the expression preceding the comment.
For example:
name: aName address: adAddress "Comment with the period outside". (extra period) self name: aName. self address: anAddressSmalltalk read as:
name: aName address: adAddress. (extra period) self name: aName. self address: anAddressThis will cause a compilation error because the first line of a method is the interface definition and it does not end with a period. (See Statements).
name: aName address: anAddressdefines two temporary variables: aName and anAddress. These temporary variables hold the arguments passed into a name:address: message.
A method can add additional temporary variables by listing the variable name enclosed in vertical bars.
For example:
| newName newAddress |
The name of a temporary variable starts with a lowercase letter and must be unique within the method. This means it cannot duplicate the name of an instance variable, a temporary variable defined in the interface, or another temporary variable.
aSampleMethod: someInput "This is just an example of method." | newValue | newValue := someInput * 2. ^newValueThis method does not have much meaning other than to illustrate a basic method layout.
aSampleMethod: someInput "This is just an example of method." ^someInput * 5The return expression first processes all statement that appear to its right and then returns the value from the last expression executed. In this example the result of the multiplication message is the return value.
ifTrue: [x := 2] ifFalse: [x := 5]You may think of a block as a mini-method within a method. As a result, the following rules apply to blocks:
ifTrue: [x := 2]is called a zero-argument block; it cannot accept any argument. However, it is possible to define a block that can take arguments such as the following:
[:varaible1 | code] [:variable1 | :variable2 | code]where variable1 and variable2 are temporary variable names and are valid only within the scope of the block. The variable name is proceded by a colon.
For example:
[:aNumber | x * aNumber]The varaible aNumber is defined within the block. This statement then multiplies a variable named x by the argument passed into the block. The variable x must be in the scope of the method in which the block resides.
More details about messages that require blocks as argument will be given in a later chapter. Further information about blocks will also be discuss in that chapter.
Example 3.3: Cascaded messages
name: aName address: anAddress phoneNumber: aPhoneNumber "set the name, address, and phone number for this student." self name: aName. self address: anAddress. self phoneNumber: aPhoneNumberSelf is the receiver of the messages for all of this method's statement. In order to execute the messages correctly, they need to appear in separate statements. Let's examine what happens when self is followed by all these keyword messages without separation:
self name: aName address: anAddress phoneNumber: aPhoneNumber.Since Smalltalk allows the grouping of all keywords together in one expression, the message name:address:phoneNumber would be sent to the receiver as a valid expression. However, this will cause an infinite number of recursive calls. To avoid this each keyword must be in a separate statement.
If the three statements are combined into one with self in front of each keyword as follows:
self name: aName self address: anAddress self phoneNumber: aPhoneNumber.Smalltalk evaluates the second self in the statement as a message sent to the object aName. It evaluates the last self as a message sent to the object anAddress. This causes an execution error since self is not a supported message by either of those two objects.
There is a coding shortcut deals with consecutive
statements. The first statement is written normanlly but all successive
statements can omit the receiving object. Each statement ends with a semicolon
(;) rather than a period., except the last statement for which the period
is optional. The method in Example 3.3 can be written as the following:
name: aName address: anAddress phoneNumber: aPhoneNumber "Set the name, address, and phone number of the student." self name: aName; address: anAddress; phoneNumber: aPhoneNumberThe first statement is normal except that it ends with a semicolon. The object receiving the last message in this sequence becomes the object receiving the first message in the next statement.
For example, the Student object has three get and set methods, one for each of its instance variables. They are
name "gets the value of name" address "gets the value of address" phoneNumber "gets the value of phoneNumber" name:aName "sets name to the value of aName" address:anAddress "sets anAddress to the value of anAddress" phoneNumber:aPhoneNumber "sets phoneNumber to the value of aPhoneNumber"Additional methods can be created from these getters and setters to combine their capabilities:
name:address: "set name and address in one message" name:address:phoneNumber: "set name, address, and phoneNumber"Getter and setter methods provide to users a common, stable interface to a class' attributes (variables). Because the implementation of these methods is hidden from users, any change to their internal processing is never a problem as long as their interface remains the same.
Go to Chapter 4: Data Operations