On Friday 25 April 2008, Jason R. wrote:
puts [1,3,5].inject() {|sum, element| sum + element} # => 9
‘sum’ in the block is a different scope from your outside ‘sum’
Jason
That’s not true, at least with ruby 1.8:
sum = 0
[1,3,5].inject() {|sum, element| sum += element}
print sum
=> 9
In ruby 1.8, if a variable with the same name as a block argument
exists, it’s
used in place of the block variable. This changed in ruby 1.9, where a
new
variable is always created, shadowing the one outside the block, as you
stated.
To understand why
print sum
prints 4, it’s necessary to understand how exactly inject works:
- the accumulator (the first block parameter) is set either to the
argument
to inject or, if it’s not given (as in this case) to the first argument
of
the array
- for each element of the array (except the first, if no argument was
given),
the block is called and the accumulator is set to the value returned by
the
block. I guess this doesn’t happen for the last element: in this case,
instead
of setting the accumulator to the return value of the block, inject
simply
returns that value.
Usually, the accumulator is a block-local variable, and so it’s
discarded
after inject returns. In this case, instead, it’s a local variable
created
outside the block. When inject changes the accumulator, it changes that
local
variable, and this is the reason it returns 4.
The correct way to use inject is to use its return value, not it’s
accumulator:
res = [1,2,3].inject(){|sum, element| sum + element}
print res
I hope this helps
Stefano