diff --git a/Chapters/PharoObjectModel/PharoObjectModel.pillar b/Chapters/PharoObjectModel/PharoObjectModel.pillar index 5aef54d..b7545c8 100644 --- a/Chapters/PharoObjectModel/PharoObjectModel.pillar +++ b/Chapters/PharoObjectModel/PharoObjectModel.pillar @@ -133,8 +133,8 @@ another object for the values of its instance variables; meta-programming is intended for writing tools like the object inspector, whose sole purpose is to look inside other objects.) -Instance variables can be accessed by name in any of the instance methods of the -class that defines them, and also in the methods defined in its subclasses. This +Instance variables can be accessed by name only by the instance methods of the +class that defines them and also in the methods defined in its subclasses. This means that Pharo instance variables are similar to ''protected'' variables in C\+\+ and Java. However, we prefer to say that they are private, because it is considered bad style in Pharo to access an instance variable directly from a @@ -184,17 +184,17 @@ This practice has some value, but it also clutters the interface of your classes its private state to the world. To ease class browsing, methods are grouped into ''protocols'' that indicate their intent. -Protocols have no semantics from the language view point. +Protocols have no semantics from the language viewpoint. They are just folders in which methods are stored. Some common protocol names have been established by convention, for example, ==accessing== for all -accessor methods and ==initialization== for establishing a consistent initial state for the object. +accessor methods and ==initialization== for establishing a consistent initial state of an object. The protocol ==private== is sometimes used to group methods that should not be seen from outside. Nothing, however, prevents you from sending a message that is implemented by such a "private" method. !!!Every class has a superclass -Each class in Pharo inherits its behaviour and the description of its structure from a single ''superclass''. +Each class in Pharo inherits the behaviour and the description of its structure from a single ''superclass''. This means that Pharo offers single inheritance. Here are some examples showing how can we navigate the hierarchy. @@ -232,8 +232,8 @@ ProtoObject superclass Traditionally the root of an inheritance hierarchy is the class ==Object== (since everything is an object). In Pharo, the root is actually a class called ==ProtoObject==, but you will normally not pay any attention to this class. -==ProtoObject== encapsulates the minimal set of messages that all objects ''must'' have and ==ProtoObject== is designed to raise as many as possible -errors (to support proxy definition). +==ProtoObject== encapsulates the minimal set of messages that all objects ''must'' have and ==ProtoObject== is designed to raise as many errors as possible +(to support proxy definition). However, most classes inherit from ==Object==, which defines many additional messages that almost all objects understand and respond to. Unless you have a very good reason to do otherwise, when creating application classes you should normally subclass ==Object==, or one of its subclasses. @@ -261,12 +261,12 @@ The caller chooses the procedure to execute ''statically'', by name. In such a case there is no lookup or dynamicity involved. In Pharo, we do ''not'' "invoke methods". Instead, we ''send messages.'' -This is just a terminology point but it is significant. It implies that this is not the responsibility of the client to select the method to be executed, it is the one of the receiver of the message. +This is just a terminology point but it is significant. It implies that it is not the responsibility of the client to select the method to be executed, but it is the one of the receiver which we send the message to. When sending a message, we do not decide which method will be executed. Instead, we ''tell'' an object to do something for us by sending it a message. A message is nothing but a name and a list of arguments. The receiver then decides how to -respond by selecting its own ''method'' for doing what was asked. Since +respond by selecting its corresponding ''method'' for doing what was asked to. Since different objects may have different methods for responding to the same message, the method must be chosen ''dynamically'', when the message is received. @@ -280,9 +280,9 @@ the method must be chosen ''dynamically'', when the message is received. ]]] As a consequence, we can send the ''same message'' to different objects, each of -which may have ''its own method'' for responding to the message. We do not tell +which may have ''its own method'' for responding to that message. We do not tell the ==SmallInteger== ==3== or the ==Point== ==(1@2)== how to respond to the -message ==\+ 4==. Each has its own method for ==\+==, and responds to ==\+ 4== +message ==\+ 4==. Each has its own method for ==\+==, and own behavior in responding to ==\+ 4== accordingly. !!!! About other computation. @@ -302,7 +302,7 @@ One of the consequences of Pharo's model of message sending is that it encourages a style in which objects tend to have very small methods and delegate tasks to other objects, rather than implementing huge, procedural methods that assume too much responsibility. Joseph Pelrine expresses this principle -succinctly as follows: +succinctly as following: @@note Don't do anything that you can push off onto someone else. @@ -312,8 +312,8 @@ providing static class operations, we simply send messages to classes (which are simply objects). In particular, since there are no ''public fields'' in Pharo, the only way to update an instance variable of another object is to send -it a message asking that it update its own field. -Of course, providing setter and getter methods for all the instance variables of an object is not good object-oriented style. +it a message asking that it updates its own field. +Of course, providing setter and getter methods for all the instance variables of an object is not a good object-oriented style. Joseph Pelrine also states this very nicely: @@note Don't let anyone else play with your data. @@ -330,7 +330,7 @@ This is a two-step process: ''method lookup'' and ''method execution''. The lookup process is quite simple: # The class of the receiver looks up the method to use to handle the message. -# If this class does not have that method defined, it asks its superclass, and so on, up the inheritance chain. +# If this class does not have that method defined, it asks to its superclass and so on, up along the inheritance chain. It is essentially as simple as that. Nevertheless there are a few questions that need some care to answer: @@ -363,7 +363,7 @@ anEllipse defaultColor >>> Color yellow ]]] -The class ==EllipseMorph== implements ==defaultColor==, so the appropriate +The class ==EllipseMorph== has the method ==defaultColor== implemented, so the appropriate method is found immediately. [[[label=scr:defaultColor|caption=A locally implemented method. @@ -373,8 +373,8 @@ EllipseMorph >> defaultColor ]]] In contrast, if we send the message ==openInWorld== to ==anEllipse==, the method -is not immediately found, since the class ==EllipseMorph== does not implement -==openInWorld==. The search therefore continues in the superclass, +is not immediately found, since the class ==EllipseMorph== does not have +==openInWorld== implemented. The search therefore continues in the superclass, ==BorderedMorph==, and so on, until an ==openInWorld== method is found in the class ==Morph== (see Figure *@fig:openInWorldLookup*). @@ -391,11 +391,11 @@ Morph >> openInWorld !!!Method execution We mentioned that sending a message is a two-step process: - ""Lookup."" First, the method having the same name as the message is looked up. -- ""Method Execution."" Second, the found method is applied to the receiver with the message arguments: When the method is found, the arguments are bound to the parameters of the method, and the virtual machine executes it. +- ""Method Execution."" Second, the found method is applied to the receiver with the message arguments: When the method is found, the arguments are bound to the parameters of the method, and then the virtual machine executes it. Now we explain the second point: the method execution. -When the lookup returns a method, the receiver of the message is bound to ==self==, and the arguments of the message to the method parameters. Then the system executes the method body. +When the lookup returns a method, the receiver of the message is bound to ==self==, and the arguments of the message are bound to the method parameters. Then the system executes the method body. This is true wherever the method that should be executed is found. Imagine that we send the message ==EllipseMorph new closestPointTo: 100@100== and that the method is defined as in Listing *@scr:closestPoing*. @@ -406,11 +406,11 @@ EllipseMorph >> closestPointTo: aPoint The variable ==self== will point to the new ellipse we created and ==aPoint== will refer to the point ==100@100==. -Now exactly the same process will happen and this even if the method found by the method lookup finds the method in a superclass. +Now the process will be exactly the same even if the method, found by the method lookup, is found in a superclass. When we send the message ==EllipseMorph new openInWorld==. The method ==openInWorld== is found in the ==Morph== class. Still the variable ==self== is bound to the newly created ellipse. -This is why we say that ==self== always represents the receiver of the message and this independently of the class in which the method was found. +This is why we say that ==self== always represents the receiver of the message and it is independent from the class in which the method was found. This is why there are two different steps during a message send: looking up the method within the class hierarchy of the message receiver and the method execution on the message receiver. @@ -424,17 +424,17 @@ When this method is not found, the virtual machine will cause the object to send +Message ==foo== is not understood.>file://figures/fooNotFound.png|label=fig:fooNotFound|width=95+ -Now, this is a perfectly ordinary, dynamic message send, so the lookup starts again from the class ==EllipseMorph==, but this time searching for the method ==doesNotUnderstand:==. -As it turns out, ==Object== implements ==doesNotUnderstand:==. +Now, this is a perfectly ordinary yet dynamic message send. So the lookup method starts again from the class ==EllipseMorph==, except that this time it searches for the method ==doesNotUnderstand:==. +As it turns out, ==Object== implements ==doesNotUnderstand:== This method will create a new ==MessageNotUnderstood== object which is capable of starting a Debugger in the current execution context. Why do we take this convoluted path to handle such an obvious error? -Well, this offers developers an easy way to intercept such errors and take alternative action. -One could easily override the method ==Object>>doesNotUnderstand:== in any subclass of ==Object== and provide a different way of handling the error. +Well, this offers developers an easy way to intercept such errors and take alternative actions. +One could easily override the method ==Object>>doesNotUnderstand:== in any subclass of ==Object== for providing a different way of handling the error. In fact, this can be an easy way to implement automatic delegation of messages from one object to another. -A ==Delegator== object could simply delegate all messages it does not understand to another object whose responsibility it is to -handle them, or raise an error itself! +A ==Delegator== object could simply delegate all messages that it does not understand to another object whose responsibility is to +handle them, or to raise an error itself! !!!About returning self @@ -445,7 +445,7 @@ whereas the method ==openInWorld== of ==Morph== does not appear to return anythi Actually a method ''always'' answers a message with a value (which is, of course, an object). The answer may be defined by the ==^== construct in the method, but if execution reaches the end of the method without executing a -==^==, the method still answers a value \-\- it answers the object that received the message. +==^==, the method will still answer a value \-\- it answers the object that received the message. We usually say that the method ''answers self'', because in Pharo the pseudo-variable ==self== represents the receiver of the message, much like the keyword ==this== in Java. Other languages, such as Ruby, by default return the value of the last statement in the method. Again, this is not the case in Pharo, instead you can imagine that a method without an explicit return ends with ==^ self==. @@ -461,12 +461,12 @@ Morph >> openInWorld ^ self ]]] -Why is explicitly writing ==^ self== not a so good thing to do? -When you return something explicitly, you are communicating that you are returning -something of interest to the sender. +Why is explicitly writing ==^ self== not a very good thing to do? +When you return something explicitly, you would be expected to return +something that is interesting to the sender. When you explicitly return ==self==, you are saying that you expect the sender to use the returned value. -This is not the case here, so it is best not to explicitly return ==self==. -We only return ==self== on special case to stress that the receiver is returned. +This is not the case here, so it is the best to not to return explicitly ==self==. +We only return ==self== on special case to emphasize that the receiver is returned. This is a common idiom in Pharo, which Kent Beck refers to as ''Interesting return value'': ''"Return a value only when you intend for the sender to use the value."'' @@ -485,9 +485,9 @@ the overridden method ''in addition to'' the new functionality we are defining i In Pharo, as in many object-oriented languages that support single inheritance, this can be done with the help of ==super== sends. A frequent application of this mechanism is in the ==initialize== method. -Whenever a new instance of a class is initialized, it is critical to also initialize any inherited instance variables. +Whenever a new instance of a class is initialized, it is critical to initialize also any inherited instance variables. However, the knowledge of how to do this is already captured in the ==initialize== methods of each of the superclass in the inheritance chain. -The subclass has no business even trying to initialize inherited instance variables! +The subclass has no business in even trying to initialize inherited instance variables! It is therefore good practice whenever implementing an ==initialize== method to send ==super initialize== before performing any further initialization as shown in Listing *@scr:morphinit*. @@ -506,8 +506,8 @@ We need ==super== sends to compose inherited behaviour that would otherwise be o !!!Self and super sends ==self== represents the receiver of the message and the lookup of the method -starts in the class of the receiver. Now what is ==super==? ==super== is -''not'' the superclass! It is a common and natural mistake to think this. It is +starts in the class of the receiver. Now what is ==super==? ==super== is +''not'' the superclass! It is a common and natural mistake to think this way. It is also a mistake to think that lookup starts in the superclass of the class of the receiver. @@ -516,9 +516,9 @@ receiver. !!!!! How do ==self== sends differ from ==super== sends? Like ==self==, ==super== represents the receiver of the message. Yes you read it -well! The only thing that changes is the method lookup. Instead of lookup -starting in the class of the receiver, it starts in the ''superclass of the -class of the method where the ==super== send occurs''. +right! The only thing that changes is the method lookup. Instead of starting +lookup in the class of the receiver, it starts in the ''superclass of the +class of the method where the ==super== send occurs''. @@important ==super== represents the receiver of the message and the method lookup starts in the superclass of the class of the method where the ==super== send occurs. @@ -743,7 +743,7 @@ Dog class >> count ]]] Now when we create a new ==Dog==, the ==count== value of the class ==Dog== is -incremented, and so is that of the class ==Hyena== (but the hyenas are counted +incremented, and so dose in the class ==Hyena== (but the hyenas are counted separately). !!!!About class ==initialize==. @@ -878,8 +878,8 @@ And indeed, until someone creates a subclass of ==WebServer==, they are the same But suppose that ==ReliableWebServer== is a subclass of ==WebServer==, and inherits the ==uniqueInstance== method. We would clearly expect ==ReliableWebServer uniqueInstance== to answer a ==ReliableWebServer==. -Using ==self== ensures that this will happen, since ==self== will be bound to the respective receiver, here the classes ==WebServer== and ==ReliableWebServer==. -Note also that ==WebServer== and ==ReliableWebServer== will each have a different value for their +Using ==self== ensures that this will happen, since ==self== will be bound to the respective receiver, here refers to the classes ==WebServer== and ==ReliableWebServer==. +Note also that ==WebServer== and ==ReliableWebServer== will have a different value for each of their ==uniqueInstance== instance variable. !!!! A note on lazy initialization. @@ -986,7 +986,7 @@ execute ==Smalltalk globals removeKey: #AGlobalName==. Sometimes we need to share some data amongst all the instances of a class and the class itself. -This is possible using ''class variables''. +This is possible by using ''class variables''. The term ''class variable'' indicates that the lifetime of the variable is the same as that of the class. However, what the term does not convey is that these variables are shared amongst all the instances of a class as well as the class itself, as shown in Figure *@fig:privateSharedVar*. Indeed, a better name would have been ''shared variables'' since this expresses more clearly their role, and also warns of the danger of using them, particularly if they are modified. @@ -1184,7 +1184,7 @@ Everything is an object, and pretty much everything happens by sending messages. -Everything is an object. Primitive entities like integers are objects, but also classes are first-class objects. -Every object is an instance of a class. Classes define the structure of their instances via ''private'' instance variables and the behaviour of their instances via ''public'' methods. Each class is the unique instance of its metaclass. Class variables are private variables shared by the class and all the instances of the class. Classes cannot directly access instance variables of their instances, and instances cannot access instance variables of their class. Accessors must be defined if this is needed. --Every class has a superclass. The root of the single inheritance hierarchy is ==ProtoObject==. Classes you define, however, should normally inherit from ==Object== or its subclasses. There is no syntax for defining abstract classes. An abstract class is simply a class with an abstract method (one whose implementation consists of the expression ==self subclassResponsibility==). Although Pharo supports only single inheritance, it is easy to share implementations of methods by packaging them as ''traits''. +-Every class has a superclass. The root of the single inheritance hierarchy is ==ProtoObject==. Classes you defined, however, should normally inherit from ==Object== or its subclasses. There is no syntax for defining abstract classes. An abstract class is simply a class with an abstract method (one whose implementation consists of the expression ==self subclassResponsibility==). Although Pharo supports only single inheritance, it is easy to share implementations of methods by packaging them as ''traits''. -Everything happens by sending messages. We do not ''call methods'', we ''send messages''. The receiver then chooses its own method for responding to the message. -Method lookup follows the inheritance chain; ==self== sends are dynamic and start the method lookup in the class of the receiver, whereas ==super== sends start the method lookup in the superclass of class in which the ==super== send is written. From this perspective ==super== sends are more static than ==self== sends. -There are three kinds of shared variables. Global variables are accessible everywhere in the system. Class variables are shared between a class, its subclasses and its instances. Pool variables are shared between a selected set of classes. You should avoid shared variables as much as possible. diff --git a/Chapters/SyntaxNutshell/SyntaxNutshell.pillar b/Chapters/SyntaxNutshell/SyntaxNutshell.pillar index 7aab1d1..2318c83 100644 --- a/Chapters/SyntaxNutshell/SyntaxNutshell.pillar +++ b/Chapters/SyntaxNutshell/SyntaxNutshell.pillar @@ -1,4 +1,4 @@ -!! Syntax in a nutshell +!! Syntax in a nutshell @cha:syntax Pharo adopts a syntax very close to that of its ancestor, Smalltalk. The syntax @@ -157,9 +157,10 @@ unary message ==close== to the same receiver. The basic classes ==Number==, ==Character==, ==String== and ==Boolean== are described in Chapter *: Basic Classes>../BasicClasses/BasicClasses.pillar@cha:basicClasses*. !!!! For the purists. -We named the language elements expressions. At the level of the compiler it is not fully correct. -For example returns are not expressions but statements. -This is a detail when learning the language and more a concern of the language compiler and designer. +We name the language elements expressions. At the level of the compiler it is not fully correct. +For example, returns are not expressions but statements. +However, this is a detail which concerns more in the aspect of language compiler and designer. + !!!Pseudo-variables @@ -219,7 +220,7 @@ Parentheses must be used to alter the order of evaluation as follows: !!!Sequences and cascades -All expressions may be composed in sequences separated by period, while message sends may be also composed in cascades by semi-colons. A period separated +All expressions may be composed in sequences separated by period or, when the messages send to the same receiver, it may also be composed in cascades by semi-colons. A period separated sequence of expressions causes each expression in the series to be evaluated as a separate ''statement'', one after the other. [[[example=true @@ -327,7 +328,7 @@ If you have a block with more than four parameters, you must use large number of parameters is often a sign of a design problem. In blocks there may be also declared local variables, surrounded by vertical bars, -just like local variable declarations in a method. Local variables are declared after arguments and vertical bar separator, and before the block body. In the following example, ==x== i ==y== are parameters, and ==z== is local variable. +just like local variable declarations in a method. Local variables are declared after arguments and vertical bar separator, and before the block body. In the following example, ==x== and ==y== are parameters, and ==z== is local variable. [[[example=true [ :x :y | @@ -337,7 +338,7 @@ just like local variable declarations in a method. Local variables are declared >>> 3 ]]] -Blocks are actually lexical closures, since they can refer to variables of the +Blocks are actually lexical closures since they can refer to variables of the surrounding environment. The following block refers to the variable ==x== of its enclosing environment: @@ -481,7 +482,7 @@ More about collections can be found in Chapter !!! Method annotations: Primitives and pragmas In Pharo methods can be annotated too. Method annotation are delimitated by ==\<== and ==\>==. -There are used for two main scenarios: execution specific metadata for the primitives of the language and +They are used for two main scenarios: execution specific metadata for the primitives of the language and metadata. !!!! Primitives @@ -528,4 +529,4 @@ Once a method has been annotated with a pragma, the annotations can be collected - Local variables declarations are delimited by vertical bars. Use ==:= == for assignment. ==\|x\| x := 1 == - Expressions consist of message sends, cascades and assignments, evaluated left to right (and optionally grouped with parentheses). Statements are expressions separated by periods. - Block closures are expressions enclosed in square brackets. Blocks may take arguments and can contain temporary variables. The expressions in the block are not evaluated until you send the block a value message with the correct number of arguments. ==[ :x | x + 2 ] value: 4== -- There is no dedicated syntax for control constructs, just messages whose sends conditionally evaluate blocks. +- There is no dedicated syntax for control constructs, but only messages send conditionally will evaluate blocks. diff --git a/Chapters/UnderstandingMessage/UnderstandingMessage.pillar b/Chapters/UnderstandingMessage/UnderstandingMessage.pillar index 8d7bee2..950de41 100644 --- a/Chapters/UnderstandingMessage/UnderstandingMessage.pillar +++ b/Chapters/UnderstandingMessage/UnderstandingMessage.pillar @@ -188,8 +188,8 @@ The three kinds of messages each have different precedence, which allows them to - 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 *@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. +Now if you want to be sure that your messages are sent in the order as you want, you can always put 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. @@ -198,7 +198,7 @@ The rest of the section illustrates each of these points. !!!!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. +We also say that unary messages have a higher priority over the other kinds of messages. @@important ==Unary > Binary > Keyword== @@ -227,7 +227,7 @@ Unfortunately the rules are a bit too simplistic for arithmetic message sends, s We will dedicate a section to arithmetic inconsistencies. -The following example, which is a bit more complex (!), offers a nice illustration that even complicated expressions can be read in a natural way: +The following example, which is a bit more complex (!), offers a nice illustration showing that even complicated expressions can be read in a natural way: [[[ [:aClass | aClass methodDict keys select: [:aMethod | (aClass>>aMethod) isAbstract ]] value: Boolean @@ -282,8 +282,8 @@ Parenthesised messages are sent prior to other messages. Here are some examples. -The first example shows that parentheses are not needed when the order is the one we want, ''i.e.'' that result is the same if we write this with or without parentheses. -Here we compute tangent of 1.5, then we round it and convert it as a string. +The first example shows that parentheses are not needed when the excution performs in the order we want, ''i.e.'' that result is the same if we write this with or without parentheses. +Here we compute tangent of 1.5, then we round it and convert it to a string. [[[example=true 1.5 tan rounded asString = (((1.5 tan) rounded) asString) @@ -302,7 +302,7 @@ The second example shows that ==factorial== is executed prior to the sum and if >>> 5040 ]]] -Similarly in the following example, we need the parentheses to force sending ==lowMajorScaleOn:== before ==play==. +Similarly, in the following example, we need the parentheses to forcely send ==lowMajorScaleOn:== before ==play==. [[[ (FMSound lowMajorScaleOn: FMSound clarinet) play @@ -333,7 +333,7 @@ Example of Parentheses. ]]] !!!!From left to right -Now we know how messages of different kinds or priorities are handled. +Now we know how message of different kinds or their 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 example == 1.5 tan rounded asString == where all unary messages are sent from left to right which is equivalent to ==(((1.5 tan) rounded) asString)==. @@ -350,7 +350,7 @@ This returns a newly created pen to which the second message ==down== is sent, a !!!!Arithmetic inconsistencies The message composition rules are simple. There is no notion of mathematical precedence because arithmetic messages are just messages as any other ones. -So their result may look in inconsistent when executed them. +So their result may look inconsistent when executed. Here we see the common situations where extra parentheses are needed. @@ -401,7 +401,7 @@ They are just binary messages, hence ==\*== does not have priority over ==\+==. +Default execution order.>file://figures/ucompoNoBracketPar.png|width=55+ -As shown in the previous example the result of this message send is not ==30== but ==110==. +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 model. To get the correct result, we should use parentheses. @@ -439,7 +439,7 @@ Note that the first rule stating that unary messages are sent prior to binary an !!!Hints for identifying keyword messages -Often beginners have problems understanding when they need to add parentheses. +Often beginners have problems understanding when do they need to add parentheses. Let's see how keywords messages are recognized by the compiler. !!!!Parentheses or not? @@ -485,22 +485,21 @@ Note that an expression can either be a message send, a variable, a literal, an Hence the conditional branches of ==ifTrue:== or ==ifTrue:ifFalse:== require blocks. Following the same principle both the receiver and the argument of a ==whileTrue:== message require the use of square brackets since we do not know how many times either the receiver or the argument should be evaluated. -Parentheses, on the other hand, only affect the order of sending messages. +Parentheses, on the other hand, are only for affecting the order of sending messages. So in ==(expression)==, the ==expression== will ''always'' be evaluated exactly once. [[[ [ x isReady ] whileTrue: [ y doSomething ] "both the receiver and the argument must be blocks" 4 timesRepeat: [ Beeper beep ] "the argument is evaluated more than once, so must be a block" -(x isReady) ifTrue: [ y doSomething ] "receiver is evaluated once, so is not a block - argument does not have to be evaluated not even once, - so it is a block" +(x isReady) ifTrue: [ y doSomething ] "the receiver is evaluated once so it is not a block but parentheses; + the argument might not be evaluated even once so it is a block" ]]] !!!Expression sequences Expressions (''i.e.'', message sends, assignments, ...) separated by periods are evaluated in sequence. Note that there is no period between a variable declaration and the following expression. The value of a sequence is the value gained by the evaluation of the last expression in the sequence. -The values returned by all the expressions except the last one are ignored at the end. +The values returned by all the expressions, except the last one, are ignored at the end. Note that the period is a separator and not a terminator. Therefore, a final period is optional. [[[ @@ -512,7 +511,7 @@ box containsPoint: 40@50 !!!Cascaded messages -Pharo offers a way to send multiple messages to the same receiver, without stating it multiple times, by using a semicolon separator (==\;==). +Pharo offers a way to send multiple messages to the same receiver, without stating it multiple times, by using a semicolon separator (==\;==). This is called the cascade in Pharo jargon. Syntactically a cascade is represented as follows: @@ -522,7 +521,7 @@ aReceiverExpression msg1 ; msg2 ; msg3 ]]] !!!!!!Examples. -You can program in Pharo without using cascades. It just forces you to repeat the receiver of the message. +You can program in Pharo without using cascades. It just will force you to repeat the receiver of the messages. The following code snippets are equivalent: [[[ Transcript show: 'Pharo is '. @@ -541,7 +540,7 @@ In fact the receiver of all the cascaded messages is the receiver of the first m Note that the object receiving the cascaded messages can itself be the result of a message send. 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 execution of ==Point new==, and ''not'' ==Point==. -The subsequent message ==isZero== is sent to that same receiver. +The subsequent message ==isZero== is then sent to that same receiver. [[[example=true Point new setX: 25 setY: 35; isZero