# Cloning arrays

**URL:** <https://www.ruby-forum.com/t/cloning-arrays/132649>\
**Category:** Ruby\
**Created:** [March 22, 2008, 2:15pm UTC](https://www.ruby-forum.com/t/cloning-arrays/132649 "2008-03-22T14:15:52Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![tarazed](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ed8c4c/32.png) [@tarazed](https://www.ruby-forum.com/u/tarazed)\
**Post date:** [March 22, 2008, 2:15pm UTC](https://www.ruby-forum.com/t/cloning-arrays/132649/1 "2008-03-22T14:15:52Z")

</div>

Another newbie question. I have started recoding some of my homegrown  
Tcl/Tk applications in Ruby/rubytk and have hit an unexpected snag when  
attempting to clone arrays. The following code is snipped verbatim from  
the program:

# Calculate coordinates for the Postscript page canvas and the

# label icons canvas in the setupInkjet window.

def User.calcxy ( disposition, f )

```
xygrid = { }

# Split the disposition string into x and y counts.
xy = Typefaces::Disposition[disposition]
# Obtain the label dimensions.
labelsize = Typefaces::Labelsizes[disposition]
# Populate the coordinate data structure.
xygrid['x'] = nx = xy[0]
xygrid['y'] = ny = xy[1]
xygrid['dx'] = dx = labelsize[0] * f
xygrid['dy'] = dy = labelsize[1] * f
# Obtain an array of 4 element arrays from the Typefaces module.
# These represent opposing corners of the address spaces on the
# Postscript canvas.
xygrid['page'] = Typefaces.labelgrid( disposition )
puts 'page coordinates'
puts xygrid['page'][0]
puts ' ______________'
# Copy the page label coordinates.
e = xygrid['page'].clone
# Shrink the label icon coordinates.
e.each { |z| z.collect! { |d| d *= f } }
# Shrink the icons further to make separations visible.
e.each { |z| z[2] -= 2.0; z[3] -= 2.0 }
# Save the label icon coordinates.
xygrid['boxes'] = e
puts 'page again'
puts xygrid['page'][0]
puts 'boxes'
puts e[0]
puts '=============='
xygrid['max'] = nx * ny
return xygrid

```

end

The diagnostics at ‘page again’ and ‘boxes’ show that the copy of the  
original array has been successfully processed but the original array  
now  
reflects the same values. The ‘page’ and ‘boxes’ arrays are to be used  
in  
different circumstances.

What am I missing? It is bound to be something simple or something  
fundamental. I tried Object#dup also - same result.

Len

---

<div class="post-metadata">

**Author:** ![tarazed](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ed8c4c/32.png) [@tarazed](https://www.ruby-forum.com/u/tarazed)\
**Post date:** [March 22, 2008, 2:36pm UTC](https://www.ruby-forum.com/t/cloning-arrays/132649/2 "2008-03-22T14:36:00Z")

</div>

On 22.03.2008 14:10, Len L. wrote:

> ```
> xygrid = { }
> # Obtain an array of 4 element arrays from the Typefaces module.
> # Shrink the icons further to make separations visible.
> 
> ```
> 
> end
> 
> The diagnostics at ‘page again’ and ‘boxes’ show that the copy of the  
> original array has been successfully processed but the original array now  
> reflects the same values. The ‘page’ and ‘boxes’ arrays are to be used in  
> different circumstances.
> 
> What am I missing? It is bound to be something simple or something  
> fundamental. I tried Object#dup also - same result:

Your issue is caused by the fact that dup and clone to shallow copies  
only, i.e. both copies of a clone Array contain the exact same  
instances. Now you modify those instances and of course changes are  
seen via both arrays:

# Shrink the label icon coordinates.

e.each { |z| z.collect! { |d| d \*= f } }

# Shrink the icons further to make separations visible.

e.each { |z| z[2] -= 2.0; z[3] -= 2.0 }

A solution would be to do

e = xygrid[‘page’].map do |z|  
z = z.map { |d| d \*= f }  
z[2] -= 2.0; z[3] -= 2.0  
z  
end

Or you can do a deep copy via the usual Marshal idiom

e = Marshal.load(Marshal.dump(xygrid[‘page’]))

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![tarazed](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ed8c4c/32.png) [@tarazed](https://www.ruby-forum.com/u/tarazed)\
**Post date:** [March 22, 2008, 2:46pm UTC](https://www.ruby-forum.com/t/cloning-arrays/132649/3 "2008-03-22T14:46:40Z")

</div>

On Saturday 22 March 2008, Len L. wrote:

> ```
> xygrid = { }
> # Obtain an array of 4 element arrays from the Typefaces module.
> # Shrink the icons further to make separations visible.
> 
> ```
> 
> Len  
> I don’t know rubytk, so I couldn’t completely follow your code, but I  
> think  
> your problem is related to the fact that clone and dup both perform  
> shallow  
> copies of the array. This means that, while the array itself is  
> duplicated,  
> its contents are not. For example, running this code

a = %w[a b c]  
b = a.dup  
puts “The ID of a is #{a.object\_id}”  
puts “The ID of b is #{b.object\_id}”  
puts “a is the same object as b? #{a.equal? b}”

puts “The ID of the contents of a: #{a.map{|i| i.object\_id}.join(’, ')}”  
puts “The ID of the contents of b: #{b.map{|i| i.object\_id}.join(’, ')}”  
a.each\_index do |i|  
puts “a[#{i}] is the same object as b[#{i}]? #{a[i].equal? b[i]}”  
end

produces:  
The ID of a is -605837488  
The ID of b is -605837528  
a is the same object as b? false  
The ID of the contents of a: -605837498, -605837508, -605837518  
The ID of the contents of b: -605837498, -605837508, -605837518  
a[0] is the same object as b[0]? true  
a[1] is the same object as b[1]? true  
a[2] is the same object as b[2]? true

This means that while a and b are not the same object (and so, you can  
modify  
one, for example adding or removing an item, leaving the other as is),  
they  
contain the same objects. So, calling ‘destructive’ methods (that is,  
methods  
which change the receiver) on the elements of one of the array will also  
change the corresponding element of the other array (because they  
contain the  
same object).

To achieve what you want, you need deep copy. As someone on this list  
recently  
pointed out, you can usually achieve this using marshal:

b = Marshal.load(Marshal.dump(a))

The problem is that with rubytk you’re dealing with a C extension, and  
with  
objects created in C, which may, or may not, work correctly with  
marshal. If  
you find out they don’t, you can try to manually deep-duplicate the  
array. In  
the simple case of my example above, you can do:

b = a.map{|i| a.dup}

If your array is a nested array, things become more complicated, as  
you’d need  
nested loops. You also need to keep in mind that object created from C  
extensions may not be clonable. In this case, there’s nothing to do.

I hope this helps

Stefano

---

<div class="post-metadata">

**Author:** ![tarazed](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ed8c4c/32.png) [@tarazed](https://www.ruby-forum.com/u/tarazed)\
**Post date:** [March 22, 2008, 3:06pm UTC](https://www.ruby-forum.com/t/cloning-arrays/132649/4 "2008-03-22T15:06:09Z")

</div>

On Sat, 22 Mar 2008 14:31:51 +0100, Robert K. wrote:

> Or you can do a deep copy via the usual Marshal idiom
> 
> e = Marshal.load(Marshal.dump(xygrid[‘page’]))
> 
> Kind regards
> 
> robert

Thanks Robert. So the issue was fundamental. I had not yet come to  
appreciate the meaning of ‘shallow copy’ or come to terms with map or  
Marshal. The Tk connection here is actually irrelevant.

That has been a great help.

Len

---

<div class="post-metadata">

**Author:** ![tarazed](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ed8c4c/32.png) [@tarazed](https://www.ruby-forum.com/u/tarazed)\
**Post date:** [March 22, 2008, 3:16pm UTC](https://www.ruby-forum.com/t/cloning-arrays/132649/5 "2008-03-22T15:16:45Z")

</div>

On Sat, 22 Mar 2008 08:37:46 -0500, Stefano C. wrote:

> On Saturday 22 March 2008, Len L. wrote:  
> 0  
> end
> 
> This means that while a and b are not the same object (and so, you can modify  
> one, for example adding or removing an item, leaving the other as is), they  
> contain the same objects. So, calling ‘destructive’ methods (that is, methods  
> which change the receiver) on the elements of one of the array will also  
> change the corresponding element of the other array (because they contain the  
> same object).
> 
> To achieve what you want, you need deep copy. As someone on this list

> b = a.map{|i| a.dup}
> 
> If your array is a nested array, things become more complicated, as

> you’d need nested loops. You also need to keep in mind that object  
> created from C extensions may not be clonable. In this case, there’s  
> nothing to do.
> 
> I hope this helps

Thanks Stefano; it sure does. I missed the earlier references to  
Marshalling - not enough time to keep up with the newsgroup. I can cope  
with nested arrays. Anyhow, many thanks for the education.

Len
