Integer accumulator behaves differently than array equivalent

Why do these accumulators behave differently?

def int_outer(a,b)
c = 0
def inner(aa,bb,cc)
cc += (aa + bb)
end
inner a, b, c
inner b, a, c
return c
end

p int_outer 3,4 #=> 0

def arr_outer(a,b)
c = []
def inner(aa,bb,cc)
cc << (aa + bb)
end
inner a, b, c
inner b, a, c
return c
end

p arr_outer 3,4 #=> [7,7]

gvim

I guess that because in the second one c is a mutable object that is
updated while in the first one is an inmutable one ovewriten.
El jun 12, 2014 8:34 a.m., “gvim” [email protected] escribió:

If I can increment an integer:

x = 1
x += 2
x #=> 3

… why doesn’t it work the same inside a method?

gvim

You’re mistaking updating the variable with mutating the object. Fixnums
in
ruby are immutable, they have no methods that can modify the object. In
fact, there’s no += method anywhere in ruby; the following lines of
code
are equivalent:

x += 1
x = x + 1

So your += just calls Fixnum#+, which returns a new object, then the
assignment updates the variable to refer to the *new object*.

Conversely, Array#<< is a method that explicitly modifies the object
in-place. For contrast, try the following example:

def arr_outer2(a,b)
c = []
def inner(aa,bb,cc)
cc += [aa + bb] # note the difference here
end
inner a, b, c
inner b, a, c
return c
end

On Thu, Jun 12, 2014 at 5:05 AM, gvim [email protected] wrote:

If I can increment an integer:

x = 1
x += 2
x #=> 3

… why doesn’t it work the same inside a method?

Every method has its own scope. This code:

def int_outer(a,b)
c = 0
def inner(aa,bb,cc)
cc += (aa + bb)
end
inner a, b, c
inner b, a, c
return c
end

…is effectively the same as this code:

def inner(aa,bb,cc)
cc += (aa + bb)
end

def int_outer(a,b)
c = 0
inner a, b, c
inner b, a, c
return c
end

…except by nesting the methods, you redefine inner each time outer is
called.

Also, I’d suggest you don’t write code like your original example where
you
define methods inside methods like that. It will blow Ruby’s method
cache,
make your code run a lot slower, and is confusing and difficult to
debug.

To get the version of your original code to increment the number, just
use
a proc instead of a method

def int_outer(a,b)
c = 0
add_and_increment_c = proc do |aa, bb|
c += aa + bb
end
add_and_increment_c.call(a, b)
add_and_increment_c.call(b, a)
return c
end