forked from SquareBracketAssociates/UpdatedPharoByExample
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUnderstandingMessage.pillar
638 lines (516 loc) · 25.2 KB
/
UnderstandingMessage.pillar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
{ "title": "Understanding message syntax" }
@cha:messages
Although Pharo's message syntax is simple, it is unconventional and can take
some time getting used to. This chapter offers some guidance to help you get
acclimatized to this special syntax for sending messages. If you already feel
comfortable with the syntax, you may choose to skip this chapter, or come back
to it later.
!!Identifying messages
In Pharo, except for the syntactic elements listed in Chapter
*: Syntax in a Nutshell>../SyntaxNutshell/SyntaxNutshell.pillar@cha:syntax*
(==\:= ^ . ; # () {} [ : | ]== ==\<== ==\>==), everything is a message send.
There is no operators, just messages sent to objects. Therefore you can define
a message named ==\+== in your class but there is also no precedence because
Pharo always takes the simplest form of definition.
The order in which messages are sent is determined by the type of message. There
are just three types of messages: ""unary"", ""binary"", and ""keyword
messages"". Pharo distinguishes such three types of messages to minimize the
number of parentheses. Unary messages are always sent first, then binary
messages and finally keyword ones. As in most languages, parentheses can be used
to change the order of execution. These rules make Pharo code as easy to read as
possible. And most of the time you do not have to think about the rules.
!!! Message structure
As most computation in Pharo is done by message passing, correctly identifying
messages is key to avoiding future mistakes. The following terminology will help
us:
- A message is composed of the message ""selector"" and the optional message arguments.
- A message is sent to a ""receiver"".
- The combination of a message and its receiver is called a ''message send'' as shown in Figure *@fig:firstScriptMessage*.
+Two message sends composed of a receiver, a method selector, and a set of arguments.>file://figures/message.png|width=70|label=fig:firstScriptMessage+
A message is always sent to a receiver, which can be a single literal, a block
or a variable or the result of evaluating another message.
To help you identify the receiver of a message, we will underline it for you. We
will also surround each message send with an ellipse, and number the message
sends starting from the first one to help you see the send order in Figure
*@fig:ellipse*.
+==aMorph color: Color yellow== is composed of two message sends: ==Color
yelow== and ==aMorph color: Color
yellow==.>file://figures/uKeyUnOne.png|width=40|label=fig:ellipse+
Figure *@fig:ellipse* represents two message sends, ==Color yellow== and
==aMorph color: Color yellow==, hence there are two ellipses. The message send
==Color yellow== is executed first, so its ellipse is numbered ==1==. There are
two receivers: 1) ==aMorph== which receives the message ==color: ...== and 2)
==Color== which receives the message ==yellow==. Both receivers are underlined.
A receiver can be the first element of a message, such as ==100== in the message
send ==100 + 200== or ==Color== in the message send ==Color yellow==. However, a
receiver can also be the result of other messages. For example in the message
==Pen new go: 100==, the receiver of the message ==go: 100== is the object
returned by the message send ==Pen new==. In all the cases, a message is sent to
an object called the ''receiver'' which may be the result of another message
send.
|!Message send |!Message type |!Action
|==Color yellow== | unary | Creates a color
|==aPen go: 100== | keyword | Forwards pen 100 pixels
|==100 + 20== | binary | 100 receives the message +
|==Browser open== | unary | Opens a new browser
|==Pen new go: 100== | un. and keyw. | Creates and moves pen 100 px
|==aPen go: 100 + 20== | keyw. and bin. | Pen moves forward 120 px
The table shows several characteristics of message sends.
- You should note that not all message sends have arguments. Unary messages like ==open== do not have arguments. Single keyword and binary messages like ==go: 100== and ==+ 20== each have one argument.
- There are also simple messages and composed ones. ==Color yellow== and ==100 + 20== are simple: a message is sent to an object, while the message send ==aPen go: 100 + 20== is composed of two messages: ==+ 20== is sent to ==100== and ==go:== is sent to ==aPen== with the argument being the result of the first message.
- A receiver can be an expression (such as an assignment, a message send or a literal) which returns an object. In ==Pen new go: 100==, the message ==go: 100== is sent to the object that results from the execution of the message send ==Pen new==.
!!Three types of messages
Pharo distinguishes between three kinds of messages to reduce mandatory
parentheses. A few simple rules based on the such different message determine
the order in which the messages are sent.
There are three different types of messages:
- ''Unary messages'' are messages that are sent to an object without any other information. For example, in ==3 factorial==, ==factorial== is a unary message.
- ''Binary messages'' are messages consisting of operators (often arithmetic). They are binary because they always involve only two objects: the receiver and the argument object. For example in ==10 + 20==, ==+== is a binary message sent to the receiver ==10== with argument ==20==.
- ''Keyword messages'' are messages consisting of one or more keywords, each ending with a colon (==:==) and taking an argument. For example in ==anArray at: 1 put: 10==, the keyword ==at:== takes the argument ==1== and the keyword ==put:== takes the argument ==10==.
!!!Unary messages
Unary messages are messages that do not require any argument. They follow the
syntactic template: ==receiver messageName==. The selector is simply made up of
a succession of characters not containing ==:== (e.g., ==factorial==,
==open==, ==class==).
[[[testcase=true
89 sin
>>> 0.860069405812453
]]]
[[[testcase=true
3 sqrt
>>> 1.732050807568877
]]]
[[[testcase=true
Float pi
>>> 3.141592653589793
]]]
[[[testcase=true
'blop' size
>>> 4
]]]
[[[testcase=true
true not
>>> false
]]]
[[[testcase=true
Object class
>>> Object class "The class of Object is Object class (BANG)"
]]]
@@important Unary messages are messages that do not require any argument. They follow the syntactic template: ==receiver selector==.
!!!Binary messages
Binary messages are messages that require exactly one argument ''and'' whose
selector consists of a sequence of one or more characters from the set: ==\+==,
==-==, ==\*==, ==/==, ==&==, ==\===, ==>==, ==|==, ==<==, ==~==, and ==@==.
Note that ==-\-== (double minus) is not allowed for parsing reasons.
[[[testcase=true
100@100
>>> 100@100 "creates a Point object"
]]]
[[[testcase=true
3 + 4
>>> 7
]]]
[[[testcase=true
10 - 1
>>> 9
]]]
[[[testcase=true
4 <= 3
>>> false
]]]
[[[testcase=true
(4/3) * 3 == 4
>>> true "equality is just a binary message, and Fractions are exact"
]]]
[[[testcase=true
(3/4) == (3/4)
>>> false "two equal Fractions are not the same object"
]]]
@@important Binary messages are messages that require exactly one argument ''and'' whose selector is composed of a sequence of characters from: ==\+==, ==-==, ==\*==, ==/==, ==\&==, ==\===, ==>==, ==|==, ==<==, ==~==, and ==@==. ==-\-== is not possible. They follow the syntactic template: ==receiver selector argument==.
!!!Keyword messages
Keyword messages are messages that require one or more arguments and whose
selector consists of one or more keywords each ending in ==:==. Keyword
messages follow the syntactic template: ==receiver selectorWordOne:
argumentOne wordTwo: argumentTwo==.
Each keyword takes an argument. Hence ==r:g:b:== is a method with three
arguments, ==playFileNamed:== and ==at:== are methods with one argument, and
==at:put:== is a method with two arguments. To create an instance of the class
==Color== one can use the method ==r:g:b:== (as in ==Color r: 1 g: 0 b: 0==),
which creates the color red. Note that the colons are part of the selector.
@@note In Java or C++, the method invocation ==Color r: 1 g: 0 b: 0== would be written ==Color.rgb(1, 0, 0)==.
[[[testcase=true
1 to: 10
>>> (1 to: 10) "creates an interval"
]]]
[[[testcase=true
Color r: 1 g: 0 b: 0
>>> Color red "creates a new color"
]]]
[[[testcase=true
12 between: 8 and: 15
>>> true
]]]
[[[testcase=true
nums := Array newFrom: (1 to: 5).
nums at: 1 put: 6.
nums
>>> #(6 2 3 4 5)
]]]
@@important Keyword messages are messages that require one or more arguments. Their selector consists of one or more keywords each ending in a colon (==:==). They follow the syntactic template: ==receiver selectorWordOne: argumentOne wordTwo: argumentTwo==.
!!Message composition
The three types of messages each have different precedence, which allows them to
be composed in an elegant way and with few parentheses.
- Unary messages are always sent first, then binary messages and finally, keyword messages.
- Messages in parentheses are sent prior to any other messages.
- Messages of the same kind are evaluated from left to right.
These rules lead to a very natural reading order. If you want to be sure
that your messages are sent in the order that you want, you can always add more
parentheses, as shown in Figure *@fig:uKeyUn*. 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.
+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:==.>file://figures/uKeyUn.png|width=70|label=fig:uKeyUn+
!!!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
types of messages.
@@important ''Rule one''. Unary messages are sent first, then binary messages, and finally keyword based messages. Unary > Binary > Keyword
As these examples show, Pharo's syntax rules generally ensure that message sends
can be read in a natural way:
[[[testcase=true
1000 factorial / 999 factorial
>>> 1000
]]]
[[[testcase=true
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:
[[[testcase=true
1 + 2 * 3
>>> 9
]]]
[[[testcase=true
1 + (2 * 3)
>>> 7
]]]
%The following example, which is a bit more complex, offers a nice
%illustration that even complicated Pharo 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 abstract. In
%fact, we could also have written the equivalent but simpler expression:
%==Boolean methodDict select: #isAbstract thenCollect: #selector==. 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 1.
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 the following script. Figure
*@fig:uKeyUn* shows graphically how messages are sent.
[[[label=scr:decColor|caption=Decomposing the evaluation of aPen color: Color yellow
aPen color: Color yellow
"unary message is sent first"
(1) Color yellow
>>> aColor
"keyword message is sent next"
(2) aPen color: aColor
]]]
!!!!!Example 2.
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). The following example shows how the
message send is executed:
[[[label=scr:decColor2|caption=Decomposing aPen go: 100 + 20
aPen go: 100 + 20
"binary message first"
(1) 100 + 20
>>> 120
"then keyword message"
(2) aPen go: 120
]]]
+Binary messages are sent before keyword
messages>file://figures/uKeyBin.png|width=30|label=fig:uKeyBin+
+Decomposing Pen new go: 100 \+
20>file://figures/uunKeyBin.png|width=30|label=fig:unKeyBin+
!!!!!Example 3.
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 *@fig:unKeyBin*).
!!!Parentheses first
Parenthesised messages are sent prior to other messages.
[[[testcase=true
3 + 4 factorial
>>> 27 "(not 5040)"
]]]
[[[testcase=true
(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."
]]]
@@important ''Rule two''. Parenthesised messages are sent prior to other messages. (Msg) > Unary > Binary > Keyword
!!!!!Example 4.
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 134x100. The
following script 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==.
+Decomposing Pen new
down>file://figures/ucompoUn.png|width=45|label=fig:unaryMessages+
[[[label=scr:decExtent|caption=Example of Parentheses.
(65@325 extent: 134@100) center
"Expression within parentheses then binary"
(1) 65@325
>>> aPoint
"binary"
(2)134@100
>>> anotherPoint
"keyword"
(3) aPoint extent: anotherPoint
>>> aRectangle
"unary"
(4) aRectangle center
>>> 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
the previous script where the two point creation messages (==@==) were sent
first.
The following script shows that execution from left to right for messages
of the same type reduces the need for parentheses.
[[[testcase=true|label=scr:Parentheses|caption=Example of Unnecessary Parentheses.
1.5 tan rounded asString = (((1.5 tan) rounded) asString)
>>> true
]]]
@@important ''Rule three''. When the messages are of the same kind, the order of evaluation is from left to right.
!!!!!Example 5.
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
*@fig:unaryMessages*.
!!!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.
[[[testcase=true
3 + 4 * 5
>>> 35 "(not 23) Binary messages sent from left to right"
]]]
[[[testcase=true
3 + (4 * 5)
>>> 23
]]]
[[[testcase=true
1 + 1/3
>>> (2/3) "and not 4/3"
]]]
[[[testcase=true
1 + (1/3)
>>> (4/3)
]]]
[[[testcase=true
1/3 + 2/3
>>> (7/9) "and not 1"
]]]
[[[testcase=true
(1/3) + (2/3)
>>> 1
]]]
!!!!!Example 6.
In the message sends ==20 \+ 2 \* 5==, there are only binary messages ==\+==
and ==\*==. However in Pharo there is no special priority for the operations
==\+== and ==\*==. They are just binary messages, hence ==\*== does not have
priority over ==\+==. Here the leftmost message ==\+== is sent first, and then
the ==*== is sent to the result as shown in the following script and Figure
*@fig:wrongcompo*.
[[[label=scr:decomposing|caption=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
]]]
+The two messages \+ and \* are of the same kind so their execution is from left to right.>file://figures/ucompoNoBracketPar.png|width=45|label=fig:wrongcompo+
As shown in the previous example 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 the price to pay for the simplicity of the
Pharo 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 by the following script and
Figure *@fig:okcompo*.
[[[label=scr:decomposing2|caption=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
]]]
+Parenthesed expressions are executed first.>file://figures/ucompoNumberBracket.png|width=45|label=fig:okcompo+
@@note 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.
+Equivalent messages using parentheses.>file://figures/uKeyUnBinPar.png|width=80|label=fig:uKeyUnBinPar+
+Equivalent messages using parentheses.>file://figures/uunKeyBinPar.png|width=80|label=fig:uunKeyBinPar+
Table : Message sends and their fully parenthesized equivalents
|!Implicit precedence |!Explicitly parenthesized equivalent
|aPen color: Color yellow | aPen color: (Color yellow)
| aPen go: 100 \+ 20 | Pen go: (100 \+ 20)
| aPen penSize: aPen penSize \+ 2 | aPen penSize: ((aPen penSize) \+ 2)
| 2 factorial \+ 4 | (2 factorial) \+ 4
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 above 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.
!!Hints for identifying keyword messages
Often beginners have problems understanding when they need to add parentheses.
Let's see how keywords messages are recognized by the compiler.
!!!Parentheses or not?
The characters \[, \], \( and \) delimit distinct areas. Within such an area, a
keyword message is the longest sequence of words terminated by ==:== that is
not cut by the characters \., or \;. When the characters \[, \], \( and \{
surround some words with colons, these words participate in the keyword message
''local'' to the area defined.
In this example, there are two distinct keyword messages:
==rotateBy:magnify:smoothing:== and ==at:put:==.
[[[
aDict
at: (rotatingForm
rotateBy: angle
magnify: 2
smoothing: 1)
put: 3
]]]
@@note The characters \[, \], \( and \) delimit distinct areas. Within such an area, a keyword message is the longest sequence of words terminated by ==:== that is not cut by the characters ==.==, or ==;==.When the characters ==[==, ==]==, ==(== and ==)== surround some words with colons, these words participate in the keyword message local to the area defined.
!!!!Precedence hints
If you have problems with these precedence rules, you may start simply by
putting parentheses whenever you want to distinguish two messages having the
same precedence.
The following piece of code does not require parentheses because the message
send ==x isNil== is unary, and is sent prior to the keyword message
==ifTrue:==.
[[[
(x isNil)
ifTrue: [...]
]]]
The following code requires parentheses because the messages
==includes:== and ==ifTrue:== are both keyword messages.
[[[
ord := OrderedCollection new.
(ord includes: $a)
ifTrue: [...]
]]]
Without parentheses the unknown message ==includes:ifTrue:== would be sent to
the collection!
!!!When to use ==[ ]== or ==( )==
You may also have problems understanding when to use square brackets (blocks)
rather than parentheses. The basic principle is that you should use ==[ ]== when
you do not know how many times, potentially zero, an expression should be
executed. ==[ expression ]== will create a block closure (an object, as always)
from ==expression==, which may be executed zero or more times, depending on the
context. (Recall from Chapter *: Syntax in a
Nutshell>../SyntaxNutshell/SyntaxNutshell.pillar@cha:syntax* that an expression
can either be a message send, a variable, a literal, an assignment or a block.)
Following this principle, the conditional branches of ==ifTrue:== or
==ifTrue:ifFalse:== require blocks. Similarly, both the receiver and the
argument of the ==whileTrue:== message require the use of square brackets since
we do not know how many times either the receiver (the loop conditional) or the
argument (the "loop body") will be executed.
Parentheses, on the other hand, only affect the order of sending messages. So in
==( expression )==, the ==expression== will ''always'' be executed exactly once.
[[[language=smalltalk
"both the receiver and the argument must be blocks"
[ x isReady ] whileTrue: [ y doSomething ]
]]]
[[[
"the argument is evaluated more than once, so must be a block"
4 timesRepeat: [ Beeper beep ]
]]]
[[[
"receiver is evaluated once, so is not a block"
(x isReady) ifTrue: [ y doSomething ]
]]]
!!Expression sequences
Expressions (i.e., message sends, assignments and so on) separated by periods
are evaluated in sequence. Note that there is no period between a variable
definition (the ==| box |== section) and the following expressions. The value of
a sequence is the value of the last expression. The values returned by all the
expressions except the last one are ignored. Note that the period is a separator
between expressions, and not a terminator. Therefore a final period is optional.
[[[testcase=true
| box |
box := 20@30 corner: 60@90.
box containsPoint: 40@50
>>> true
]]]
!!Cascaded messages
Pharo offers a way to send multiple messages to the same receiver using a
semicolon (==;==). This is called the cascade in Pharo jargon. It follows
the pattern: ==expression msg1; msg2==
[[[
Transcript show: 'Pharo is '.
Transcript show: 'fun '.
Transcript cr.
]]]
''is equivalent to:''
[[[
Transcript
show: 'Pharo is';
show: 'fun ';
cr
]]]
Note that the object receiving the cascaded messages can itself be the result of
a message send. In fact, the receiver of all the cascaded messages is the
receiver of the first message involved in a cascade. In the following example,
the first cascaded message is ==setX:setY== since it is followed by a cascade.
The receiver of the cascaded message ==setX:setY:== is the newly created point
resulting from the evaluation of ==Point new==, and ''not'' ==Point==. The
subsequent message ==isZero== is sent to that same receiver.
[[[testcase=true
Point new setX: 25 setY: 35; isZero
>>> false
]]]
@@important ==expression msg1. expression msg2== is equivalent to ==expression msg1; msg2==
!!Chapter summary
-A message is always sent to an object named the ''receiver'', which itself may be the result of other message sends.
-There are three types of messages: ''unary'', ''binary'', and ''keyword''.
-Unary messages are messages that do not require any argument. They are of the form of ==receiver selector==.
-Binary messages are messages that involve two objects, the receiver and another object, whose selector is composed of one or more characters from the following list: ==\+==, ==-==, ==\*==, ==/==, ==|==, ==&==, =====, ==>==, ==<==, ==~==, and ==@==. They are of the form: ==receiver selector argument==.
-Keyword messages are messages that involve more than one object and that contain at least one colon character (==:==). They are of the form: ==receiver selectorWordOne: argumentOne wordTwo: argumentTwo==.
-""Rule One."" Unary messages are sent first, then binary messages, and finally keyword messages.
-""Rule Two."" Messages in parentheses are sent before any others.
-""Rule Three."" When the messages are of the same type, the order of evaluation is from left to right.
-In Pharo, traditional arithmetic operators such as \+ and \* have the same priority. ==\+== and ==\*== are just binary messages, therefore ==\*== does not have priority over ==\+==. You must use parentheses to obtain the desired arithmetical order of operations.