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 value

11.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.