Skip to main content
Engineering LibreTexts

3.6: Conditionals and Loops in a Nutshell

  • Page ID
    36347
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    Smalltalk offers no special syntax for control constructs. Instead, these are typically expressed by sending messages to booleans, numbers and collections, with blocks as arguments.

    Conditionals are expressed by sending one of the messages ifTrue:, ifFalse: or ifTrue:ifFalse: to the result of a boolean expression. See Chapter 8 for more about booleans.

    (17 * 13 > 220)
        ifTrue: [ 'bigger' ]
        ifFalse: [ 'smaller' ] → 'bigger'
    

    Loops are typically expressed by sending messages to blocks, integers or collections. Since the exit condition for a loop may be repeatedly evaluated, it should be a block rather than a boolean value. Here is an example of a very procedural loop:

    n := 1.
        [ n < 1000 ] whileTrue: [ n := n*2 ].
        n → 1024
    

    whileFalse: reverses the exit condition.

    n := 1.
        [ n > 1000 ] whileFalse: [ n := n*2 ].
        n → 1024
    

    timesRepeat: offers a simple way to implement a fixed iteration:

    n := 1.
        10 timesRepeat: [ n := n*2 ].
        n → 1024
    

    We can also send the message to:do: to a number which then acts as the initial value of a loop counter. The two arguments are the upper bound, and a block that takes the current value of the loop counter as its argument:

    result := String new.
        1 to: 10 do: [:n | result := result, n printString, ' '].
        result → '12345678910'
    

    High-Order Iterators. Collections comprise a large number of different classes, many of which support the same protocol. The most important messages for iterating over collections include do:, collect:, select:, reject:, detect: and inject:into:. These messages define high-level iterators that allow one to write very compact code.

    An Interval is a collection that lets one iterate over a sequence of numbers from the starting point to the end. 1 to: 10 represents the interval from 1 to 10. Since it is a collection, we can send the message do: to it. The argument is a block that is evaluated for each element of the collection.

    result := String new.
        (1 to: 10) do: [:n | result := result, n printString, ' '].
        result → '12345678910'
    

    collect: builds a new collection of the same size, transforming each element.

    (1 to: 10) collect: [ :each | each * each] → #(149162536496481100)
    

    select: and reject: build new collections, each containing a subset of the elements satisfying (or not) the boolean block condition. detect: returns the first element satisfying the condition. Don’t forget that strings are also collections, so you can iterate over all the characters.

    'hello there' select: [ :char | char isVowel ] → 'eoee'
    'hello there' reject: [ :char | char isVowel ] → 'hll thr'
    'hello there' detect: [ :char | char isVowel ] → $e
    

    Finally, you should be aware that collections also support a functional-style fold operator in the inject:into: method. This lets you generate a cumulative result using an expression that starts with a seed value and injects each element of the collection. Sums and products are typical examples.

    (1 to: 10) inject: 0 into: [:sum: each |sum + each] → 55
    

    This is equivalent to 0+1+2+3+4+5+6+7+8+9+10.

    More about collections can be found in Chapter 9.


    This page titled 3.6: Conditionals and Loops in a Nutshell is shared under a CC BY-SA 3.0 license and was authored, remixed, and/or curated by Andrew P. Black, Stéphane Ducasse, Oscar Nierstrasz, Damien Pollet via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.