I am not sure about the meaning of "...but not the objects they reference" in both the documantion of ruby
and rubinus
.
In ruby-doc, there is the explanation of #clone
and #dup
behavior saying:
Produces a shallow copy of obj—the instance variables of obj are
copied, but not the objects they reference. Copies the frozen and
tainted state of obj. See also the discussion under Object#dup.
The same is repeated in the implementation of Rubinius:
Copies instance variables, but does not recursively copy the objects
they reference. Copies taintedness.
I tried out with the following code, but the behavior is out of my expectation.
class Klass
attr_accessor :array
end
s1 = Klass.new
ar = [1, 2, 3]
s1.array = [ar]
s2 = s1.clone
# according to the doc,
# s2.array should be initialized with empty Array
# however the array is recursivley copied too
s2.array.equal? s1.array # true
In Ruby, all objects are references. Take a look at the following example:
class Klass
attr_accessor :a
end
s1 = Klass.new
a = [1,2,3]
s1.a = a
s2 = s1.clone
s1.a.object_id #=> 7344240
s2.a.object_id #=> 7344240
You can see that both of the arrays are the same object, and are both references to the array living somewhere in the heap. In a deep copy, the array itself would have been copied, and the new s2
would have its own, distinct array. The array is not copied, just referenced.
Note:
Here's what it looks like if you do a deep copy:
s3 = Marshal.load(Marshal.dump(s1)) #=> #<Klass:0x00000000bf1350 @a=[1, 2, 3, 4], @bork=4>
s3.a << 5 #=> [1, 2, 3, 4, 5]
s1 #=> #<Klass:0x00000000e21418 @a=[1, 2, 3, 4], @bork=4>
The "equal?" comparison checks whether they are exactly the same object:
- The == comparison checks whether two values are equal
- eql? checks if two values are equal and of the same type
- equal? checks if two things are one and the same object.
for example :
a=[1,2]
=> [1, 2]
a == [1,2]
=> true
a.eql? [1,2]
=> true
a.equal? [1,2]
=> false
a.equal? a
=> true
As you are testing using equal? it shows the copy has not made an object with the array being uninitialized, but it has made the copied object point to the same array as the original. If it recursively copied the opjects s2.array would have the same contents as s1.array but would be a different object so:
s2.array.equal? s1.array # false
s2.array.eql? s1.array # true