Control Structures as Messages
There are no control statements in Smalltalk syntax.
There are no control statements in Smalltalk syntax. Conditionals and loops are messages sent to booleans, blocks, and numbers.
11.1 Conditionals
ifTrue: without ifFalse: returns nil when the condition is false.
How it works — True and False are subclasses of Boolean, each with its own method:
Polymorphism replaces the if statement. (The compiler inlines these messages for speed, but the semantics are as shown.)
x > 0 ifTrue: [ 'positive' ] ifFalse: [ 'non-positive' ].
x > 0 ifTrue: [ Transcript show: 'yes' ].
x isNil ifTrue: [ x := 0 ].
x := (a > b) ifTrue: [ a ] ifFalse: [ b ]. "it's an expression"
x ifNil: [ 'nothing' ] ifNotNil: [ :value | value printString ].
x ifNotNil: [ :v | v doSomething ].
list ifEmpty: [ 'empty' ] ifNotEmpty: [ :l | l first ].True >> ifTrue: trueBlock ifFalse: falseBlock
^ trueBlock value
False >> ifTrue: trueBlock ifFalse: falseBlock
^ falseBlock value11.2 Loops
"Counting loops"
1 to: 5 do: [ :i | Transcript show: i printString; cr ].
10 to: 1 by: -2 do: [ :i | Transcript show: i printString; space ].
5 timesRepeat: [ Transcript show: '*' ].
"Conditional loops — the receiver is a block, so it can be re-evaluated"
| n |
n := 1.
[ n < 1000 ] whileTrue: [ n := n * 2 ].
[ n <= 1 ] whileFalse: [ n := n // 2 ].
[ (n := n + 1) < 10 ] whileTrue. "body-less form"
"Infinite loop with explicit exit (inside a method)"
[ | line | line := stream nextLine. line isNil ifTrue: [ ^ self ]. self process: line ] repeat.11.3 Iterating collections
Prefer collection iterators over index loops (Chapter 21).
#(3 4 5) do: [ :each | Transcript show: each printString ] separatedBy: [ Transcript show: ', ' ].
#(3 4 5) doWithIndex: [ :each :i | Transcript show: i printString, '=', each printString; cr ].
#(3 4 5) reverseDo: [ :each | Transcript show: each printString ].11.4 Case-like dispatch
Smalltalk prefers polymorphism over switch. When you need a lookup table, use a dictionary of blocks:
Squeak and Pharo also provide caseOf: (x caseOf: { [1] -> ['one']. [2] -> ['two'] } otherwise: ['many']), but it is rarely idiomatic.
| actions |
actions := Dictionary new
at: #add put: [ :a :b | a + b ];
at: #mul put: [ :a :b | a * b ];
yourself.
(actions at: #mul) value: 6 value: 7. "→ 42"
(actions at: #pow ifAbsent: [ [ :a :b | 0 ] ]) value: 2 value: 3.11.5 Inlined messages
The compiler inlines a handful of messages when their arguments are literal blocks: ifTrue:, ifFalse:, ifTrue:ifFalse:, ifNil: variants, and:, or:, whileTrue:, whileFalse:, to:do:, to:by:do:, timesRepeat: and repeat. Consequence: you cannot meaningfully override ifTrue: in your own class and expect it to be called with literal blocks.