Next: Iteration, Up: Code blocks (I)
Let’s first add some code to keep you from writing too many checks. We will simply update our current method for the Checking class; if you have entered the methods from the previous chapters, the old definition will be overridden by this new one.
Checking extend [ writeCheck: amount [ | num | (checksleft < 1) ifTrue: [ ^self error: 'Out of checks' ]. num := checknum. checknum := checknum + 1. checksleft := checksleft - 1. self spend: amount ^ num ] ]
The two new lines are:
(checksleft < 1) ifTrue: [ ^self error: 'Out of checks' ].
At first glance, this appears to be a completely new structure. But, look again! The only new construct is the square brackets, which appear within a method and not only surround it.
The first line is a simple boolean expression. checksleft
is our integer, as initialized by our Checking class.
It is sent the message <
, and the argument 1. The current
number bound to checksleft
compares itself against 1, and
returns a boolean object telling whether it is less than 1.
Now this boolean, which is either true or false, is sent the
message ifTrue:
, with an argument which is called a code
block. A code block is an object, just like any other. But
instead of holding a number, or a Set, it holds executable
statements. So what does a boolean do with a code block which
is an argument to a ifTrue:
message? It depends on which boolean!
If the object is the true
object, it executes the code
block it has been handed. If it is the false
object, it
returns without executing the code block. So the traditional
conditional construct has been replaced in
Smalltalk with boolean objects which execute the indicated
code block or not, depending on their truth-value.
30
In the case of our example, the actual code within the
block sends an error message to the current object. error:
is handled by the parent class Object, and will pop up an
appropriate complaint when the user tries to write too many
checks. In general, the way you handle a fatal error in
Smalltalk is to send an error message to yourself (through
the self
pseudo-variable), and let the error handling
mechanisms inherited from the Object class take over.
As you might guess, there is also an ifFalse:
message
which booleans accept. It works exactly like ifTrue:
,
except that the logic has been reversed; a boolean false
will execute the code block, and a boolean true
will not.
You should take a little time to play with this method of representing conditionals. You can run your checkbook, but can also invoke the conditional functions directly:
true ifTrue: [ 'Hello, world!' printNl ] false ifTrue: [ 'Hello, world!' printNl ] true ifFalse: [ 'Hello, world!' printNl ] false ifFalse: [ 'Hello, world!' printNl ]
It is interesting to note that because of the way conditionals are done, conditional constructs are not part of the Smalltalk language, instead they are merely a defined behavior for the Boolean class of objects.
Next: Iteration, Up: Code blocks (I)