As I was reading the latest entry in Brett Hallett's blog, titled "Rewriting a script into a callable method", I saw the code:
i := 20.
d := '0123456789abcdefghijklmnopqrstuvwxyz'.
l := d size.
s := String new: i.
1 to: i do: [ :x |
s at: x put: (d at: (Random between: 1 and: l))
].
s printNl.
This code didn't look very smalltalk-like to me. So I thought a bit about what was striking me odd, and it was all those explicit #at: and #at:put: calls. Not to mention confusing uses of "i" and "l" in a bad font. :)
The first two lines aren't bad. I'd keep them, although I'd probably name the values a bit more intention-revealing:
desiredLength := 20.
sourceCharacterSet := '0123456789abcdefghijklmnopqrstuvwxyz'.
But the rest of the code starts going a bit odd. Consider the expression:
d at: (Random between: 1 and: (d size))
(factoring out the temp variable). This is equivalent to simply:
d atRandom
And the loop there is collecting together "desiredLength" number of these random selections. So let's say that using a Collection-style method instead:
(1 to: desiredLength) collect: [:each | sourceCharacterSet atRandom]
We're now much closer to the result. The problem is that we now have an OrderedCollection of Characters, not a string. But a simple class-mapping will fix that, because Strings know how to create themselves from Collections of Characters:
((1 to: desiredLength) collect: [:each | sourceCharacterSet atRandom]) as: String
And there we have it. If #collect: didn't barf on a 0-arg block, we wouldn't need the misleading ":each" in there either. (Developed with
Squeak... not sure how unstandard this stuff is, or if it's just missing in GNU Smalltalk.)