Skip to main content
Engineering LibreTexts

4.3: Message Composition

  • Page ID
    36350
  • \( \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}}\)

    The three kinds of messages each have different precedence, which allows them to be composed in an elegant way.

    1. Unary messages are always sent first, then binary messages and finally keyword messages.
    2. Messages in parentheses are sent prior to any kind of messages.
    3. Messages of the same kind are evaluated from left to right.

    These rules lead to a very natural reading order. Now if you want to be sure that your messages are sent in the order that you want you can always put more parentheses as shown in Figure \(\PageIndex{1}\). In this figure, the message yellow is an unary message and the message color: a keyword message, therefore the message send Color yellow is sent first. However as message sends in parentheses are sent first, putting (unnecessary) parentheses around Color yellow just emphasizes that it will be sent first. The rest of the section illustrates each of these points.

    Equivalence of parentheses.
    Figure \(\PageIndex{1}\): Unary messages are sent first so Color yellow is sent. This returns a color object which is passed as argument of the message aPen color:.

    Unary > Binary > Keywords

    Unary messages are sent first, then binary messages, and finally keyword messages. We also say that unary messages have a higher priority over the other kinds of messages.

    Rule One

    Unary messages are sent first, then binary messages, and finally keyword based messages.

    Unary > Binary > Keyword

    As these examples show, Smalltalk’s syntax rules generally ensure that message sends can be read in a natural way:

    1000 factorial / 999 factorial    → 1000
    2 raisedTo: 1 + 3 factorial       → 128
    

    Unfortunately the rules are a bit too simplistic for arithmetic message sends, so you need to introduce parentheses whenever you want to impose a priority over binary operators:

    1 + 2 * 3    → 9
    1 + (2 * 3)  → 7
    

    The following example, which is a bit more complex (!), offers a nice illustration that even complicated Smalltalk expressions can be read in a natural way:

    [:aClass | aClass methodDict keys select: [:aMethod | (aClass>>aMethod) isAbstract ]]
        value: Boolean −→ an IdentitySet(#or: #| #and: #& #ifTrue: #ifTrue:ifFalse:
        #ifFalse: #not #ifFalse:ifTrue:)
    

    Here we want to know which methods of the Boolean class are abstract1. We ask some argument class, aClass, for the keys of its method dictionary, and select those methods of that class that are abstract. Then we bind the argument aClass to the concrete value Boolean. We need parentheses only to send the binary message >>, which selects a method from a class, before sending the unary message isAbstract to that method. The result shows us which methods must be implemented by Boolean’s concrete subclasses True and False.

    Example. In the message aPen color: Color yellow, there is one unary message yellow sent to the class Color and a keyword message color: sent to aPen. Unary messages are sent first so the message send Color yellow is sent (1). This returns a color object which is passed as argument of the message aPen color: aColor (2) as shown in Code \(\PageIndex{1}\). Figure \(\PageIndex{1}\) shows graphically how messages are sent.

    Code \(\PageIndex{1}\) (Squeak): Decomposing the evaluation of aPen color: Color yellow

    aPen color: Color yellow
    (1)         Color yellow  "unary message is sent first"
                → aColor
    (2) aPen color: aColor    "keyword message is sent next"
    

    Example. In the message aPen go: 100 + 20, there is a binary message + 20 and a keyword message go:. Binary messages are sent prior to keyword messages so 100 + 20 is sent first (1): the message + 20 is sent to the object 100 and returns the number 120. Then the message aPen go: 120 is sent with 120 as argument (2). Code \(\PageIndex{2}\) shows how the message send is executed.

    Code \(\PageIndex{2}\) (Squeak): Decomposing aPen go: 100 + 20

    aPen go: 100 + 20
    (1)      100 + 20    "binary message first"
             → 120
    (2) aPen go: 120     "then keyword message"
    
    Binary messages are sent before keyword messages.
    Figure \(\PageIndex{2}\): Binary messages are sent before keyword messages.
    Decomposing Pen new go: 100 + 20.
    Figure \(\PageIndex{3}\): Decomposing Pen new go: 100 + 20.

    Example. As an exercise we let you decompose the evaluation of the message Pen new go: 100 + 20 which is composed of one unary, one keyword and one binary message (see Figure \(\PageIndex{3}\)).

    Parentheses first

    Rule Two

    Parenthesised messages are sent prior to other messages.

    (Msg) > Unary > Binary > Keyword

    1.5 tan rounded asString = (((1.5 tan) rounded) asString)    → true "parentheses
        not needed here"
    3 + 4 factorial      → 27 "(not 5040)"
    (3 + 4) factorial    → 5040
    

    Here we need the parentheses to force sending lowMajorScaleOn: before play.

    (FMSound lowMajorScaleOn: FMSound clarinet) play
    "(1) send the message clarinet to the FMSound class to create a clarinet sound.
     (2) send this sound to FMSound as argument to the lowMajorScaleOn: keyword
         message.
     (3) play the resulting sound."
    

    Example. The message (65@325 extent: 134 @ 100) center returns the center of a rectangle whose top left point is \( (65, 325) \) and whose size is \( 134 \times 100 \). Code \(\PageIndex{3}\) shows how the message is decomposed and sent. First the message between parentheses is sent: it contains two binary messages 65@325 and 134@100 that are sent first and return points, and a keyword message extent: which is then sent and returns a rectangle. Finally the unary message center is sent to the rectangle and a point is returned. Evaluating the message without parentheses would lead to an error because the object 100 does not understand the message center.

    Code \(\PageIndex{3}\) (Squeak): Example of Parentheses

    (65 @ 325 extent: 134 @ 100) center
    (1) 65@325                            "binary"
        → aPoint
    (2)               134@100             "binary"
                      → anotherPoint
    (3) aPoint extent: anotherPoint       "keyword"
        → aRectangle
    (4) aRectangle center                 "unary"
        → 132@375
    

    From left to right

    Now we know how messages of different kinds or priorities are handled. The final question to be addressed is how messages with the same priority are sent. They are sent from the left to the right. Note that you already saw this behaviour in Code \(\PageIndex{3}\) where the two point creation messages (@) were sent first.

    Rule Three

    When the messages are of the same kind, the order of evaluation is from left to right.

    Example. In the message sends Pen new down all messages are unary messages, so the leftmost one, Pen new, is sent first. This returns a newly created pen to which the second message down is sent, as shown in Figure \(\PageIndex{4}\).

    Decomposing Pen new down.
    Figure \(\PageIndex{4}\): Decomposing Pen new down.
    Message decomposition.

    Arithmetic inconsistencies

    The message composition rules are simple but they result in inconsistency for the execution of arithmetic message sends expressed in terms of binary messages. Here we see the common situations where extra parentheses are needed.

    3 + 4 * 5        → 35 "(not 23) Binary messages sent from left to right"
    3 + (4 * 5)      → 23
    1 + 1/3          → (2/3) "and not 4/3"
    1 + (1/3)        → (4/3)
    1/3 + 2/3        → (7/9) "and not 1"
    (1/3) + (2/3)    → 1
    

    Example. In the message sends 20 + 2 * 5, there are only binary messages + and *. However in Smalltalk there is no specific priority for the operations + and *. They are just binary messages, hence * does not have priority over +. Here the leftmost message + is sent first (1) and then the * is sent to the result as shown in Code \(\PageIndex{4}\).

    Message decomposition.
    Equivalent messages using parentheses.
    Figure \(\PageIndex{5}\): Equivalent messages using parentheses.

    Code \(\PageIndex{4}\) (Squeak): Decomposing 20 + 2 * 5

    "As there is no priority among binary messages, the leftmost message + is evaluated
        first even if by the rules of arithmetic the * should be sent first."
    
        20 + 2 * 5
    (1) 20+2    → 22
    (2) 22 *5   → 110
    

    As shown in Code \(\PageIndex{4}\) the result of this message send is not 30 but 110. This result is perhaps unexpected but follows directly from the rules used to send messages. This is somehow the price to pay for the simplicity of the Smalltalk model. To get the correct result, we should use parentheses. When messages are enclosed in parentheses, they are evaluated first. Hence the message send 20 + (2 * 5) returns the result as shown in Code \(\PageIndex{5}\).

    Code \(\PageIndex{5}\) (Squeak): Decomposing 20 + (2 * 5)

    "The messages surrounded by parentheses are evaluated first therefore * is sent prior
        to + which produces the correct behaviour."
    
        20 + (2 * 5)
    (1)      (2 * 5)    → 10
    (2) 20 + 10         → 30
    

    In Smalltalk, arithmetic operators such as + and * do not have different priority. + and * are just binary messages, therefore * does not have priority over +. Use parentheses to obtain the desired result.

    Note that the first rule stating that unary messages are sent prior to binary and keyword messages avoids the need to put explicit parentheses around them. Table \(\PageIndex{1}\) shows message sends written following the rules and equivalent message sends if the rules would not exist. Both message sends result in the same effect or return the same value.

    Table \(\PageIndex{1}\): Message sends and their fully parenthesized equivalents.
    Implicit precedence Explicitly parenthesized equivalent
    aPen color: Color yellow aPen color: (Color yellow)
    aPen go: 100 + 20 aPen go: (100 + 20)
    aPen penSize: aPen penSize + 2 aPen penSize: ((aPen penSize) + 2)
    2 factorial + 4 (2 factorial) + 4

    1. In fact, we could also have written the equivalent but simpler expression: Boolean methodDict select: #isAbstract thenCollect: #selector

    This page titled 4.3: Message Composition 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.