Inject is just an iterator:
% echo "sum=0; [1,2,3,4,5].inject{|sum,e| sum+e }" | parse_tree_show -f
[[:lasgn, :sum, [:lit, 0]],
[:iter,
[:call,
[:array, [:lit, 1], [:lit, 2], [:lit, 3], [:lit, 4], [:lit, 5]],
:inject],
[:masgn,
[:array,
[:lasgn, :sum], # <<<<<
[:dasgn_curr, :e]]],
[:call, [:lvar, :sum], :+, [:array, [:dvar, :e]]]]]
Because sum was assigned initially outside of the inject, it is an lvar (local variable) instead of a dvar (dynamic/iter var, like e). You'll notice that the assignments to both of those variables happens before the call, and is part of the iteration mechanics itself. There is no assignment done at the end of an iteration.
I think it is more important to point out that inject is _just_another_iterator_. There is nothing special about it or how it works. It is just a simple each just like everything else in Enumerable. This makes the ruby implementation cleaner and easier to maintain. Sum isn't an accumulator, as much as it is just another variable. Should map or reject have some special semantics attached to their block variables?
If you really are stuck on this idea, you can always change "sum+e" to read "sum+=e" but at that stage, why use an inject at all?
Here is our implementation from metaruby:
def inject(memo = :_nothing)
enum = self.to_a.dup
memo = enum.shift if memo == :_nothing
return memo if enum.empty?
enum.each do |item|
memo = yield memo, item
end
return memo
end
···
On Aug 7, 2006, at 12:36 AM, Peña, Botp wrote:
Hi All,
inject is a powerful method in ruby. but the ff gives me surprise..
irb(main):001:0> sum=0
=> 0
irb(main):002:0> [1,2,3,4,5].inject{|sum,e| sum+e }
=> 15
irb(main):003:0> sum
=> 10