From: Sam Griffith Date: 2002-11-06T15:04:33+09:00 Subject: Re: Thoughts on Ruby >> withAllChildrenDo: aBlock >> aBlock value: self. >> children ifNotNil: [children do: [:c | c withAllChildrenDo: >> aBlock]]! ! >> >> As I said before, I don't "get" Smalltalk. However, what I can see >> here is that there's four different symbols (!, :, |, []), and at >> least one of them does double-duty (:). It's not very clear at all >> -- in a reading sense -- what this does. I suspect that the >> equivalent Ruby is more readable, not least because it uses fewer >> symbols. I use both Ruby and I have used Smalltalk since 1987. So I thought I'd explain this code above a bit.... Maybe it'll help just to understand. Quickly, the "!" character isn't actually part of Smalltalk code. The person who gave you this got it from a fileout of source. The "!" characters are used by the file parser as markers for the method boundaries or when "! !" is encountered, the end of the fileout source (EOF). You never use "!" in Smalltalk code. Short course in Smalltalk syntax and reading the code. There are the following type of messages: Unary => 5 abs. "The message to the object takes no arguments" Binary => 5 + 2. "This message takes one argument" Keyword => 5 between: 2 and: 10 "This message has the arguments mixed in with the message syntax at each keyword. Each keyword is ended by a colon" "." ends a statement. ":=" does assignment. Parenthesis group message evaluation order. Normal evaluation order is left to right. [] is a block closure. These are full closures. Blocks express the fact that they can bind input arguments by having a input variable specification that is expressed like so: [:blockVariable | ...code....]. The vertical bar separates the block variables section of the block from the code of the block. The colon character before the block variable signifies that it is a input variable to the block. Blocks can be executed by sending them the value message or one of it's derivatives, value:, value:value:, value:value:value:. For example: AddOneBlock := [:valueToAddOneTo | valuetoAddOneTo + 1]. Transcript show: (AddOneBlock value: 5). Above I use parenthesis to group the block to get the "value:" message before passing the result to the "show:" method. Had I not done that, the parsing rule about moving from left to right would have had me believing that there was a message that the Transcript understood called: "show:value:". When put into Smalltalk and executed, the Transcript (aka - Console) will show 6 as the output. Now, what is going on with this code: >> withAllChildrenDo: aBlock >> aBlock value: self. >> children ifNotNil: [children do: [:c | c withAllChildrenDo: >> aBlock]] So this code wants all the children of some object to have aBlock (of code) evaluated on them. First off, they evaluate the block on the current object. (aBlock value: self) This follows the syntax I explained up above. Next they have a message that takes a block as an argument to the message "ifNotNil:" Somewhere in that message that block will get evaluated by being sent a value message or its' derivatives discussed above. The block that is passed has one input variable ":c" which is bound to one of the children and then recursively calls this method. So the syntax in this code is the following: Keyword messages, "." (the period end of statement), a Block variable (:c), and blocks themselves. Smalltalk only has something like 7 syntactical elements in the language. The code above falls right into the basic pattern; receiver message args. For this line of code: "aBlock value: self" the receiver is "aBlock", the message is "value:" and the arg is "self". For this line of code: "children ifNotNil: [children do: [:c | c withAllChildrenDo: aBlock]] The receiver is "children", the message is "ifNotNil:" and the arg is "[children do: [:c | c withAllChildrenDo: aBlock]]. Notice that that last argument has a nested block in it. That nested block won't be evaluated until the arg is evaluated inside the "ifNotNil" message. (This is the call chain of the messages) Hopefully understanding that Blocks are just object receiving the value messages, this well help you read the code easier. Hope this helps those of you trying to read Smalltalk. It has been my experience in teaching Smalltalk for many years, that once you get used to reading from left to right and understand the basic message types that you can learn to read any Smalltalk code in about 5 minutes. You just apply some basic rules over and over just like a very basic parser.... I hope that this helps some people. Thanks, -- Sam Griffith Jr. email: staypufd@mac.com Web site: http://homepage.mac.com/staypufd/index.html