Messages in Smalltalk
0..9.each { ... }"
Are you sure that wouldn't be more equivalent to this in Ruby?
1.upto(10) {|n| puts "do stuff with #{n}" }
You are quite right. In terms of what gets executed, to:do: is like upto(), though arrays in Smalltalk are 1-based, and it looks like the arrays in Ruby are 0-based. So I just translated between the two. With foo, you went from 0 to 9. The idea was to create a range that could be used to cause something to happen 10 times, and where the index could be used.
When I wrote that, I was thinking of it creating what's called an Interval in Smalltalk (equivalent to a range in Ruby), but I just looked at the implementation, and it just iterates on the block in situ.
Does that mean that to: is a range constructor while do is an iterator, the way .. is a range constructor in Ruby while upto and each are iterators?
In this case, no, but it would be possible to carry out the same actions in concept using an interval, using the messages you had guessed. If I wanted to create the interval and then use that to iterate, I'd have to make that clear:
(1 to: 10) do: [:n | "do something here"]
To indicate that I want "1 to: 10" evaluated, and then the result sent another message, I have to put parentheses around "1 to: 10" which act as a delimiter between the messages (and cause the inner expression to be evaluated before the outer one), or assign the interval to a variable and then send do: to the instance the variable holds. In this case to: creates the interval, and do: is a message to the interval instance, giving it a block to iterate over.
There's no real reason to do this in this case. I'm just illustrating a distinction. There are two methods I could've used in the Number class: one called to:, which creates an interval, and to:do:, which iterates on the block in place.
To clarify further, the parameterized message construction syntax works like this:
obj keyword1: param1 keyword2: param2 keyword3: param3 ...
That's considered all one message, with however many parameters, to "obj". If there wasn't a to:do: method in the Number class, and I said:
1 to: 10 do: [ ... ]
I'd get a "does not understand" exception, because Smalltalk would think I was trying to send a single message with two parameters, called to:do:, to the SmallInteger called "1" (Number is a base class to SmallInteger).
In many instances these rules for messages work out really nicely, producing code that looks poetic in its elegance. In some cases it gets really ugly... I think it depends on how much work has been done on a library, and in some cases the Smalltalk parser, to really take into account how the functionality is going to be used.