A little bit confused about array+array addition (bug or expected behavior?)

G

gga

irb> a = [1,2]
=> [1, 2]
irb> a
=> [1, 2, 3, 4]
irb(main):082:0> a
=> [1, 2, 3, 4]

So far so good...


irb(main):082:0> def add(x)
irb(main):084:1> x += [5,6]
irb(main):085:1> end

irb(main):087:0> add(a)
=> [1, 2, 3, 4, 5, 6]
irb(main):088:0> a
=> [1, 2, 3, 4] ===>>> uh? am I not passing stuff by reference?
where is 5, 6?


irb(main):089:0> def add2(x)
irb(main):089:0> x << [5,6]
irb(main):089:0> end

irb(main):090:0> add2(a)
=> [1, 2, 3, 4, [5, 6]]
irb(main):091:0> a
=> [1, 2, 3, 4, [5, 6]] ==> seems logical, but then .... why +=
behaves differently?
ruby 1.8.2 (2004-12-25) [i686-linux]
 
F

Florian Gross

gga said:
irb(main):082:0> def add(x)
irb(main):084:1> x += [5,6]
irb(main):085:1> end

irb(main):087:0> add(a)
=> [1, 2, 3, 4, 5, 6]
irb(main):088:0> a
=> [1, 2, 3, 4] ===>>> uh? am I not passing stuff by reference?
where is 5, 6?

You are not passing variables by reference, you are passing objects by
reference.

Ruby does not have a built-in way of doing variable by reference as
variables are usually not first-class objects. (They are names for objects.)

You probably want to do x.replace(x + [5, 6]) or x.push(5, 6) which
modify the object itself.

This has come up frequently in the past -- if you are willing to do a
bit of research on google groups you will find implementations of
first-class variable objects, using lambdas for modifying variables in
other scopes and more.
 
A

Assaph Mehr

gga said:
irb(main):082:0> def add(x)
irb(main):084:1> x += [5,6]
irb(main):085:1> end

irb(main):087:0> add(a)
=> [1, 2, 3, 4, 5, 6]
irb(main):088:0> a
=> [1, 2, 3, 4] ===>>> uh? am I not passing stuff by reference?
where is 5, 6?

In the method body you are reassing to the local variable x.
.. x += [...]
is translated to:
.. x = x + [...]
and #+ as we all know returns a copy of the object.

You can see this with:

.. def add(x)
.. puts "Before #{x.object_id}"
.. x += [5,6]
.. puts "After #{x.object_id}"
.. end

So you ARE passing by ref, but then changing the ref to point to
anotehr object.
irb(main):089:0> def add2(x)
irb(main):089:0> x << [5,6]
irb(main):089:0> end

irb(main):090:0> add2(a)
=> [1, 2, 3, 4, [5, 6]]
irb(main):091:0> a
=> [1, 2, 3, 4, [5, 6]] ==> seems logical, but then .... why +=
behaves differently?

The METHOD #<< modifies the object in place. The SYNTACTIC SUGAR += is
changing a objeced referred to.

HTH,
Assaph
 
G

gga

Yes, that's what I had figured. I had not realized the existance of
the replace method. That's exactly what I was looking for.
 
R

Robert Klemme

Assaph Mehr said:
irb(main):082:0> def add(x)
irb(main):084:1> x += [5,6]
irb(main):085:1> end

irb(main):087:0> add(a)
=> [1, 2, 3, 4, 5, 6]
irb(main):088:0> a
=> [1, 2, 3, 4] ===>>> uh? am I not passing stuff by reference?
where is 5, 6?

In the method body you are reassing to the local variable x.
. x += [...]
is translated to:
. x = x + [...]
and #+ as we all know returns a copy of the object.

You can see this with:

. def add(x)
. puts "Before #{x.object_id}"
. x += [5,6]
. puts "After #{x.object_id}"
. end

So you ARE passing by ref, but then changing the ref to point to
anotehr object.
irb(main):089:0> def add2(x)
irb(main):089:0> x << [5,6]
irb(main):089:0> end

irb(main):090:0> add2(a)
=> [1, 2, 3, 4, [5, 6]]
irb(main):091:0> a
=> [1, 2, 3, 4, [5, 6]] ==> seems logical, but then .... why +=
behaves differently?

The METHOD #<< modifies the object in place. The SYNTACTIC SUGAR += is
changing a objeced referred to.

Alternative is #concat
a=[1,2] => [1, 2]
def add3(a) a.concat [3,4] end => nil
add3 a => [1, 2, 3, 4]
a
=> [1, 2, 3, 4]


Regards

robert
 
Y

YANAGAWA Kazuhisa

In Message-Id: <[email protected]>
gga said:
Yes, that's what I had figured. I had not realized the existance of
the replace method. That's exactly what I was looking for.

But what you need in this particular case is Array#concat.

irb(main):001:0> a=[1,2,3]
=> [1, 2, 3]
irb(main):002:0> a.concat([4,5])
=> [1, 2, 3, 4, 5]
irb(main):003:0> a
=> [1, 2, 3, 4, 5]
 
S

Stefan Lang

gga said:
irb(main):082:0> def add(x)
irb(main):084:1>    x += [5,6]

This creates a new array and assigns it to the local variable x.
The original array passed into this method won't be modified.
But the result of the statement is the new array, which will
be returned.
irb(main):085:1> end

irb(main):087:0> add(a)
=> [1, 2, 3, 4, 5, 6]
irb(main):088:0> a
=> [1, 2, 3, 4]        ===>>> uh?  am I not passing stuff by reference?
where is 5, 6?


irb(main):089:0> def add2(x)
irb(main):089:0>   x << [5,6]

<< appends to the existing array
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top