Reputation: 41
I saved an array sequence
to reset
. I deleted each element from sequence
, performing an operation, then reset sequence
to its former state.
reset = sequence
(0..sequence.length).each do |i|
puts "Sequence #{sequence}, index is #{i}. Deleting #{sequence[i]}"
sequence.delete_at(i)
puts "New sequence is #{sequence.inspect}, sorted makes #{sequence.sort}, unique makes #{sequence.uniq}"
return true if sequence.sort == sequence && sequence.uniq == sequence
puts "This is reset before the sequence = reset: #{reset.inspect}"
sequence = reset
puts "Resetting sequence. Reset is #{reset.inspect}, sequence is #{sequence.inspect}"
dummy = gets.chomp
end
Then, what happened to sequence
also happened to reset
. Here is some output:
Sequence [1, 1, 1, 2, 3], index is 0. Deleting 1
New sequence is [1, 1, 2, 3], sorted makes [1, 1, 2, 3], unique makes [1, 2, 3]
This is reset before the sequence = reset: [1, 1, 2, 3]
Resetting sequence. Reset is [1, 1, 2, 3], sequence is [1, 1, 2, 3]
It's mucking about reset
when I only commanded it to delete from sequence
. It's not the case that reset = sequence
is inside the loop. What gives? The loop was supposed to break at oldarray.size
, inside which it was pushing elements into a new array. But inexplicably, it pushed the same numbers into the same array as well, thereby creating an infinite loop.
Upvotes: 0
Views: 94
Reputation: 110665
Suppose we write
sequence = [1, 1, 1, 2, 3]
reset = sequence
#=> [1, 1, 1, 2, 3]
The variables sequence
and reset
do not only hold the same value, they hold the same object:
sequence.object_id
#=> 4044000
reset.object_id
#=> 4044000
Note that variables do not have object id's; it is their values--Ruby objects-- that have unique ids (see Object#object_id). When we write sequence.object_id
, sequence
returns [1, 1, 1, 2, 3]
and then [1, 1, 1, 2, 3].object_id #=> 4044000
is returned.
If the object [1, 1, 1, 2, 3]
is changed the values of the two variables will both equal the changed object.
sequence.replace [1, 4]
#=> [1, 4]
sequence.object_id
#=> 4044000
reset
#=> [1, 4]
reset.object_id
#=> 4044000
On the other hand, if we set either of these variables to equal a difference object (which will have a different object id), the value of the other variable is unaffected.
sequence = [99, 31]
sequence.object_id
#=> 5564720
reset
#=> [1, 4]
reset.object_id
#=> 4044000
Upvotes: 0
Reputation: 28850
reset
and sequence
are the same array. The =
operator doesn't copy the contents of an array or other object; it creates a new reference to the same array.
For example, try this in irb
:
irb(main):001:0> a = [ 10, 20 ]
=> [10, 20]
irb(main):002:0> b = a
=> [10, 20]
irb(main):003:0> a
=> [10, 20]
irb(main):004:0> b
=> [10, 20]
irb(main):005:0> a.push( 30 )
=> [10, 20, 30]
irb(main):006:0> b.push( 40 )
=> [10, 20, 30, 40]
irb(main):007:0> a
=> [10, 20, 30, 40]
irb(main):008:0> b
=> [10, 20, 30, 40]
The same is true when you pass an array or any object in a method call. The method doesn't get a separate copy of the object data; it receives a reference to the same object:
irb(main):001:0> a = [ 10, 20 ]
=> [10, 20]
irb(main):002:0> def foo( x ); x.push( 30 ); end
=> :foo
irb(main):003:0> foo( a )
=> [10, 20, 30]
irb(main):004:0> a
=> [10, 20, 30]
Note that foo
didn't just modify its x
parameter, it also modified the a
that was passed into it, because x
and a
are both references to the same array.
If you want to make a copy of an array so that operations on it are independent of the original, you can use dup
or clone
:
irb(main):001:0> a = [ 10, 20 ]
=> [10, 20]
irb(main):002:0> b = a.clone
=> [10, 20]
irb(main):003:0> a
=> [10, 20]
irb(main):004:0> b
=> [10, 20]
irb(main):005:0> a.push( 30 )
=> [10, 20, 30]
irb(main):006:0> b.push( 40 )
=> [10, 20, 40]
irb(main):007:0> a
=> [10, 20, 30]
irb(main):008:0> b
=> [10, 20, 40]
Many languages work like this; the assignment operator or a function parameter doesn't copy any data but merely creates a new reference to the same data.
Here's the same example in Python:
>>> a = [ 10, 20 ]
>>> b = a
>>> a
[10, 20]
>>> b
[10, 20]
>>> a.append( 30 )
>>> b.append( 40 )
>>> a
[10, 20, 30, 40]
>>> b
[10, 20, 30, 40]
and in JavaScript:
a = [ 10, 20 ]
(2) [10, 20]
b = a
(2) [10, 20]
a.push( 30 ) // .push() returns the array length
3
b.push( 40 )
4
a
(4) [10, 20, 30, 40]
b
(4) [10, 20, 30, 40]
Upvotes: 3