Collecting Smalltalk idioms
marcel at system.de
Tue Aug 10 19:42:31 UTC 1999
> From: merlyn at stonehenge.com (Randal L. Schwartz)
> >>>>> "Marcel" == Marcel Weiher <marcel at system.de> writes:
> Marcel> Turning it into the standard #do:separatedBy: would then look
> Marcel> something like this:
> Marcel> do:operation separatedBy:separator
> Marcel> self inject:  into: [ :divider :each |
> Marcel> divider value.
> Marcel> operation value:each.
> Marcel> separator
> Marcel> ].
> This seems "unclean" to me. We're sending a needless "value" to an
> empty block.
> I'd rather see something like:
> do: operation separatedBy: separator
> self inject: true into: [ :firstTime :each |
> firstTime ifFalse: [separator value].
> operation value: each.
> If you'll indulge me. It'll probably even bytecompile tighter. :)
I have to say, I disagree :-)
My code happens to be slightly shorter in source, which makes it
'cleaner' to my eyes, proving once again that 'cleanliness' seems to
be a very subjective measure...
As to efficency, mine does have one extra block evaluation, but
yours has N extra if-tests, and you are saved from N extra block
evaluations only by a compiler optimization. Assuming that the extra
block evaluation is more expensive than the if-evaluation by some
finite factor, your code should be faster for collections of less
than (time-to-eval-block / time-to-eval-if elements) , whereas my
code should be asymptotically faster.
To find out, I implemented both and timed them. For a very small
interval ( 1 to:10 ), yours was faster by 2.1%, but at (1 to:100)
mine was faster by 4.5%, confirming my conjecture. The crossover
point seems to be at around 25 elements (so empty block evaluation is
25 times more expensive than an if test?). Strangely enough, the
difference gets smaller again with larger intervals, with (1
to:1million) for example clocking in at only 2.5% in my favor (I
figure general overhead such as GC kicks in).
More information about the Squeak-dev