From: ara.t.howard@... Date: 2006-11-16T00:09:10+09:00 Subject: Re: Design problem with 'inject' On Wed, 15 Nov 2006, Gary Boone wrote: > Ruby's inject has a design that can lead to hard to find bugs. The > problem is that you don't have to specify what is summed; the value of > the block is summed. That means 'next' can lead to a bug. Here's an > example: > > No problem: > > arr.inject(0) do |sum, i| > sum += i > done > > But suppose you need to skip some elements, so you add a 'next' > statement. > Problem: > > arr.inject(0) do |sum, i| > next if (i==3) > sum += i > done > > This breaks. If i is 3, then when the next occurs, the value of the > block is nil. The value of the block is added to sum, but because "+" > isn't defined for nil, there's an exception. Note that this isn't due to > the line "sum += i"; it's due to the design of inject: the value of the > block is added to sum. > > The real problem is that 'inject' has two semantics: 1) it adds onto sum > using an explicit "sum +=" or 2) is adds the value of the block. A > better approach would be allow only one way to accumulate. That way, you > can't make a change that inexplicitly changes the function from one > semantics to another. this last part is dead wrong, the semantics of inject have __nothing__ to do with summing, or even accumulating __anything__. the semantics of inject is merely that it iterates an enumerable, on the first iteration it passes |arg, enumerable_element| to the block, and on subsequent passes |value_of_previous_block_call, enumerable_element| is passedy for example keys = %w( foo bar foobar ) index = keys.inject({}){|hash, k| hash.update k => true} so, you see, inject itself does in fact do exactly one thing. if you happen to do more in the block it's no fault of inject. -a -- my religion is very simple. my religion is kindness. -- the dalai lama