On Aug 7, 2006, at 12:36 AM, Pe, 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

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