Explain a piece of Smalltalk code?

I can not understand this piece of Smalltalk code:

[(line := self upTo: Character cr) size = 0] whileTrue. 

Can someone help explain this?

+6
smalltalk
source share
4 answers

One simple thing, if you have an image where the code came from, launches the debugger on it and goes through.

If you come across a code out of context, for example, on a mailing list, you can view the performers of one of the messages and see what it does. For example, #size and #whileTrue are pretty standard, so we'll skip them for now, but #upTo: sounds interesting. It reminds me of stream methods, and educating developers, he confirms it (in Pharo 1.1.1), ReadStream defines it. There is no comment for the method, but OmniBrowser shows a small arrow next to the method name indicating that it is defined in the superclass. If we check the immediate superclass, PositionableStream, there is a good method comment explaining what this method does, which is nobody from the stream, before reaching the object specified by the argument.

Now, if we logically analyze the code, it seems that it:

  • reads a string from a stream (i.e. before cr)
    • if it is empty (size = 0), the loop continues
    • If not, returns

Thus, the code skips all empty lines and returns the first non-empty. To confirm, we could pass it a stream in a multi-line line and run it like this:

 line := nil. paragraph := ' this is a line of text. this is another line line number three' readStream. [(line := paragraph upTo: Character cr) size = 0] whileTrue. line. "Returns 'this is a line of text.'" 
+12
source share

Is this more readable:

 while(!strlen(line=gets(self))) 

The above expression is flawed if feof or any other error, line == NULL
So what does the Smalltalk expression have if the end of the stream is encountered, upTo: will respond to an empty collection, and you will have an infinite loop if you do not have a special stream that causes an error at the end of the stream ... Try

 String new readStream upTo: Character cr 
+1
source share

Smalltalk priority rules - this is the first: unary messages
second: binary messages
third: keyword messages
last: left to right

This order can be changed from left to right using parentheses (for example, parentheses). First, the expression inside the pair of brackets is evaluated. If the inserts are copied, the evaluation of the innermost bracket is first performed, then it goes out to the outer bracket and, finally, the remainder of the expression outside the brackets.

Due to the strong trend from left to right, I often find it helpful to read the expression from right to left.

So, for [(line := self upTo: Character cr) size = 0] whileTrue.

Approaching from the end to the beginning, we get the following interpretation.

. Complete the expression. Equivalent in C or Java

whileTrue What's immediately to his left? ] closing the block object.

So, whileTrue is a unary message sent to the block [ ... ] ie keep doing this block while the block evaluates to true

The block returns the result of the last expression evaluated in the block.

The last expression in the block size = 0 comparison. And a binary message.

size usually a unary message sent to the recipient. So, we check the size of something to see if it is 0 . If something has a size of 0 , keep moving.

What do we check size ? The expression immediately to the left of the message name. To the left of size is (line := self upTo: Character cr)

This is what we want to know by size.

So, time to put this expression under the knife.

(line := self upTo: Character cr) - task. line will have the result self upTo: Character cr .

What is at the right end of this expression? cr This is a unary message, therefore has the highest priority. What is he going to. that is, what is the receiver for the cr message?

Immediately on the left is Character . So send the Character class a cr message. This evaluates to an instance of the Character class with a value of 13 — that is, a carriage return character.

So now we get to self upTo: aCarriageReturn

If self - the object receiving the message self upTo: aCarriageReturn - does not understand the name of the message sizeUpto: it throws an exception.

So, if this is code from a working system, we can conclude that self should be an object that understands sizeUpto: At this point, I am often tempted to find a massage name to see which classes have a message called sizeUpto: in the list of message names that they know and understand (i.e. their message protocol).

(In this case, it did not help me - it is not a method in any of the classes of my Smalltalk system).

But self seems to be asked to deal with a character string containing (potentially) many many carriage returns.

So, return the first part of aCharacterString with respect to the first carriage return.

If the length of aCharacterString from the beginning to the first carriage return is zero, continue moving and do it all again.

So, it seems that we are dealing with concatenation of several lines with cr-terminated and process each one in turn until we find one that is not empty (except for carriage return) and assigns it line

+1
source share

One thing about Smalltalk, in which I personally am not a fan, is that although messaging is used sequentially to do almost everything, it can sometimes be difficult to determine which message is being sent to any receiver. This is because Smalltalk does not have any separators around messages (for example, Objective-C) and instead allows you to associate messages with messages, following a set of priority rules that go something like this: "messages are sent interpreted from left to right, and if they are not limited to parentheses, messages with many keywords are processed first, then binary keyword messages, then unary, and then no keywords. " Of course, using temporary variables or even just parentheses to make the order of explicit messages, you can reduce the number of situations when you need to think about this order of operations. The following is an example of the code above, broken into several lines, using temporary variables and parentheses to explicitly organize messages for readability. I think this is a little clear about the intent of the code:

 line = (self upTo: (Character cr)). ([((line size) = 0)] whileTrue). 

So basically a line is a line created by combining the characters in the line self up to the carriage return character (cr character). Then we check the size of the string in characters and check if it is 0, and because we put it in a block (brackets), we can send it a whileTrue, which re-evaluates the condition in the block until it returns true. So yes, while True would indeed be clearer if it were called doWhileTrue or something like that.

Hope this helps.

-2
source share

All Articles