The problem with the above approach is that an array holds also references
to the contained objects. So if you are changing what objects the array contains
your approach is fine. If you are changing the contained objects
themselves, then
you have the same problem, since dup makes a shallow copy:
irb(main):001:0> a = %w{one two three}
=> ["one", "two", "three"]
irb(main):002:0> a.map {|x| x.object_id}
=> [-606229548, -606229578, -606229608]
irb(main):003:0> b = a.dup
=> ["one", "two", "three"]
irb(main):004:0> b[0] = "new value"
=> "new value"
irb(main):005:0> a
=> ["one", "two", "three"]
irb(main):006:0> b
=> ["new value", "two", "three"]
irb(main):007:0> b.map {|x| x.object_id}
=> [-606260528, -606229578, -606229608]
As you can see here, both a and b are referencing the same
string objects in their second and third position. So the strings
"two" and "three" are the same objects in both arrays. If you
change *those objects* the change will be reflected in both
arrays:
irb(main):008:0> a[2].upcase!
=> "THREE"
irb(main):009:0> a
=> ["one", "two", "THREE"]
irb(main):010:0> b
=> ["new value", "two", "THREE"]
If you want to avoid this, you need b to be a deep copy of a.
One way to achieve it is with Marshal:
irb(main):011:0> c = Marshal.load(Marshal.dump(a))
=> ["one", "two", "THREE"]
irb(main):012:0> c.map {|x| x.object_id}
=> [-606348068, -606348078, -606348088]
irb(main):014:0> a[2].downcase!
=> "three"
irb(main):015:0> a
=> ["one", "two", "three"]
irb(main):016:0> b
=> ["new value", "two", "three"]
irb(main):017:0> c
=> ["one", "two", "THREE"]
Although you should read a bit more on Marshal to understand if
it suits your needs.
Hope this helps,
Jesus.
···
On Wed, Aug 27, 2008 at 9:10 AM, Adam Akhtar <adamtemporary@gmail.com> wrote:
Hi after a bit of searching and reading im quite confused by this.
I first learnt C so used to being able to pass by reference or by value.
In Ruby its just by reference (so ive just found out after an hour of
chasing a bug).
I have an array of ojbects which are baisically acting like structures.
I want to pass the array to a function. This function will take the
array, make a new copy so as to protect the original from any changes.
Changes will be made to the copy and then the copy is returned.
How do i do that?