0

When I try to pop an element from an array, it pops. When I assign that array to another variable before popping and then if I pop, the pop operation affects both the arrays.

For example:

 ruby-1.9.2-p290 :339 > a= [1,2,3]
     => [1, 2, 3] 
    ruby-1.9.2-p290 :340 > b = a
     => [1, 2, 3] 
    ruby-1.9.2-p290 :341 > a
     => [1, 2, 3] 
    ruby-1.9.2-p290 :342 > b
     => [1, 2, 3] 
    ruby-1.9.2-p290 :343 > a.pop
     => 3 
    ruby-1.9.2-p290 :344 > a
     => [1, 2] 
    ruby-1.9.2-p290 :345 > b
     => [1, 2] #WHY?
    ruby-1.9.2-p290 :346 > x = [1,2,3]
     => [1, 2, 3] 
    ruby-1.9.2-p290 :347 > y = x
     => [1, 2, 3] 
    ruby-1.9.2-p290 :348 > z = x
     => [1, 2, 3] 
    ruby-1.9.2-p290 :349 > y
     => [1, 2, 3] 
    ruby-1.9.2-p290 :350 > z
     => [1, 2, 3] 
    ruby-1.9.2-p290 :351 > y.pop
     => 3 
    ruby-1.9.2-p290 :352 > y
     => [1, 2] 
    ruby-1.9.2-p290 :353 > z
     => [1, 2] # WHY?
    ruby-1.9.2-p290 :354 > x
     => [1, 2] 
    ruby-1.9.2-p290 :355 > 

If I use pop, all the variables are affected. How do I keep the original array and pop from the other one only?

Dharman
  • 30,962
  • 25
  • 85
  • 135
beck03076
  • 3,268
  • 2
  • 27
  • 37

3 Answers3

6

If you assign an array to a new variable, it's not copied, but you only set a reference to the original array. If you want to keep the original array, you have to clone it by using dup:

ruby-1.9.2-p180 :001 > a = [1,2,3]
 => [1, 2, 3] 
ruby-1.9.2-p180 :002 > b = a.dup
 => [1, 2, 3] 
ruby-1.9.2-p180 :003 > b.pop
 => 3 
ruby-1.9.2-p180 :004 > a
 => [1, 2, 3] 
ruby-1.9.2-p180 :005 > b
 => [1, 2] 
Mischa
  • 42,876
  • 8
  • 99
  • 111
3

The assignment operator in ruby is making a copy of the value only if it deal with POD (Plain Old Data) objects like numbers, strings. In other cases, it simply copies the reference to the object.

And don't forget, that dup (and clone) method makes only shallow copy of object. It means that if your array have other non-POD objects inside, they won't be copied.

inner = [1,2,3]
 => [1, 2, 3]
outer = [inner, 7,8,9]
 => [[1, 2, 3], 7, 8, 9]

outer_dup = outer.dup
inner.pop
 => 3

outer
 => [[1, 2], 7, 8, 9]
outer_dup
 => [[1, 2], 7, 8, 9]

You can avoid it by overriding clone method to handle making deep copy by yourself.

Flexoid
  • 4,155
  • 21
  • 20
0

Ruby is very object oriented. With very few exceptions, Ruby almost always passes variables by reference, not value. It's a pretty important concept. Check this out. It isn't ruby, but it might help demystify it a bit. Hope that helps!

Christopher WJ Rueber
  • 2,141
  • 15
  • 22
  • -1. This wrong. First off, Ruby is pass-by-value. Secondly, there are no exceptions, Ruby is *always* pass-by-value. If you want to know whether Ruby (or any other language) is pass-by-reference or pass-by-value, just try it out: `def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"`. – Jörg W Mittag May 01 '12 at 14:21
  • 1
    After reading other posts that you've made on this subject, it's clear that you're adhering to a strict Computer Science sense of the word. That just flat out doesn't make sense in this case. The OP is asking a question about passing an object around. Please consider being less pedantic. – Christopher WJ Rueber May 01 '12 at 15:24
  • I'm talking about Ruby, which doesn't even *have* primitives, only objects. I provided a simple test program in my comment which you can cut&paste into IRb yourself if you don't believe me. – Jörg W Mittag May 01 '12 at 15:24