Previous Table of Contents Next


This version has the disadvantage that it uses a hard-coded constant for the default value. Clearly, such constants should be avoided to improve both readability and maintainability of code. Preferably, we would use a symbolic constant such as this one:

  creditLimit := DefaultCreditLimit. “set to default value”

This can be accomplished by declaring DefaultCreditLimit as a class variable of Customer. A class variable is a variable that is shared by all the instances of a class and by the class object. A class variable is also shared by the instances and class objects of any subclasses. A name of a class variable is globally visible to all instance and class methods of a class and its superclass. Because class variables have a relatively global scope, their names are, by convention, usually capitalized.

One remaining issue is the initialization of customerCount and DefaultCreditLimit. For the methods name:address:customerNumber: to work properly, these variables must be initialized to some appropriate numeric objects. By convention, class objects are usually initialized by a class method with the selector named initialize. Such a method for Customer might be as follows:

  initialize
      “Initialize class and class instance variables”
      DefaultCreditLimit := 500.
      customerCount := 0.

This method would be invoked by an expressions such as this one:

  Customer initialize.

This expression would need to be executed before the first usage of Customer within a program.

Using class methods, class instance variables, and class variables, the definition of Customer now has this complete template:

Class Name Customer
Super Class Object
Instance Variables name address customerNumber creditLimit
Instance Methods
name: initName address: initAddr: customerNumber: initNumber
“initialize the state of the receiver to the argument values”
name := initName.
Address := initAddr.
customerNumber := initNumber
name
“return the name of the customer”
^name
address
“return the current address from the receiver”
^address
Class Instance Variables customerCount
Class Methods
initialize
“Initialize class and class instance variables”
DefaultCreditLimit := 500.
CustomerCount := 0
name: initName address: initAddr customerNumber: initNumberM.tt
“create and initialize a new instance using the argument values”
| c |
c := self new.
^ c name: initName address: initAddr customerNumber: initNumber

4.4. Control Structures

A Smalltalk program consists of a set of class definitions that define the objects that will be sent messages to perform the function of the program. The actual computational logic of the program is encoded in the objects’ methods and is expressed as sequences of message sends. Pure sequential execution of message sends is insufficiently powerful for solving all but the simplest programming problems. Most interesting algorithms require the capability to conditionally or iteratively execute code. Programming languages usually support this by providing specialized statements for specifying conditional and iterative execution. Smalltalk does not use such statements, however. In Smalltalk, all computation except assignment is expressed using message sends. Even conditional and iterative execution is accomplished using message sends. This is possible because of the power of polymorphism.

4.4.1. Conditional Execution

In Smalltalk, a conditional is usually expressed using a message with the selector ifTrue:ifFalse:. The receiver of this message should be one of the boolean objects, true or false. The arguments must be objects that implement the message value. For example, a simple conditional might be

  booleanValue ifTrue: trueAction ifFalse: falseAction.

In this example, booleanValue is assumed to be a variable whose value is one of the boolean objects. trueAction and falseAction are assumed to be objects that respond to the message value. More commonly such an expression would be written as a compound message expression in which the receiver of ifTrue:ifFalse: is an expression that evaluates to true or false. Consider the following line, for example:

  A>B ifTrue: trueAction ifFalse: falseAction.

If the receiver of ifTrue:ifFalse: is true, the message value is sent to the first argument, and the result of that message is returned as the result of the ifTrue:ifFalse: message. If the receiver is false, the value is sent to the second argument, and its result is returned as the value of ifTrue:ifFalse:.

A conditional message such as ifTrue:ifFalse: can be implemented solely using polymorphism without requiring any other special language constructs. The key to this is to implement true and false as instances of different classes with different methods for the selector ifTrue:ifFalse:. If true is an instance of the class named True and false is an instance of the class named False, the definitions of the methods ifTrue:ifFalse: would be as follows:

Class True Instance Method
ifTrue: trueAction ifFalse: ignoredAction
“Because the receiver is known to be true, return the result of
evaluating the first argument. The second argument is ignored.”
^trueAction value

Class False Instance Method
ifTrue: ignoredAction ifFalse: falseAction
“Because the receiver is known to be false,
evaluating the second argument. The first
argument is ignored
^falseAction value


Previous Table of Contents Next