# Cloning object with array members

**URL:** <https://www.ruby-forum.com/t/cloning-object-with-array-members/81288>\
**Category:** Ruby\
**Created:** [January 6, 2007, 7:31pm UTC](https://www.ruby-forum.com/t/cloning-object-with-array-members/81288 "2007-01-06T19:31:04Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Shea\_M](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ecccb3/32.png) [@Shea\_M](https://www.ruby-forum.com/u/Shea_M)\
**Post date:** [January 6, 2007, 7:31pm UTC](https://www.ruby-forum.com/t/cloning-object-with-array-members/81288/1 "2007-01-06T19:31:04Z")

</div>

Consider a simple class like this:  
class MyClass  
def initialize  
@var1 = ‘’  
@arr1 = []  
end  
end

Now if I have an instance of MyClass, and want to clone it, what is the  
‘cleanest’ way to do this?

a = MyClass.new  
b = a.clone

This method leaves ‘b.arr1’ pointing to the same data as a.arr1.

Hmmm… I’ll try overriding clone, and manually deal with the arrays:

def clone  
rslt = super.clone  
end

This blows the stack, I believe because all methods are inherited  
virtually.

Ok, so now I have to manually copy everything in clone, whatever, I am  
getting sick of this:

def clone  
rslt = MyClass.new  
rslt.var1 = @var1  
rslt.arr1 = @arr1.clone  
rslt  
end

Turns out this does not compute either, as there is no method var1= or  
arr1= ! I want to keep var1 private, so can’t go this route either.

One more attempt:  
def clone  
rslt = MyClass.new

```
 self.instance_variables.each do |member|
   rslt.instance_variable_set( member,

```

self.instance\_variable\_get(member).clone )  
end  
end

This fails as the methos do not seem to copy over.

There has to be a simple way to do something like this? What is common  
recipe for something like this? Should this really be that hard in  
ruby?

~S

---

<div class="post-metadata">

**Author:** ![Shea\_M](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ecccb3/32.png) [@Shea\_M](https://www.ruby-forum.com/u/Shea_M)\
**Post date:** [January 19, 2007, 4:30pm UTC](https://www.ruby-forum.com/t/cloning-object-with-array-members/81288/2 "2007-01-19T16:30:44Z")

</div>

Hi –

On Sat, 6 Jan 2007, Shea M. wrote:

> ‘cleanest’ way to do this?
> 
> a = MyClass.new  
> b = a.clone
> 
> This method leaves ‘b.arr1’ pointing to the same data as a.arr1.

I don’t see an a.arr1 method. Did you mean to create some accessors  
methods?

The most common idiom I’ve seen for deep copying is:

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

David

---

<div class="post-metadata">

**Author:** ![Shea\_M](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ecccb3/32.png) [@Shea\_M](https://www.ruby-forum.com/u/Shea_M)\
**Post date:** [January 19, 2007, 4:30pm UTC](https://www.ruby-forum.com/t/cloning-object-with-array-members/81288/3 "2007-01-19T16:30:53Z")

</div>

On Jan 5, 2007, at 4:40 PM, Shea M. wrote:

> Hmmm… I’ll try overriding clone, and manually deal with the arrays:
> 
> There has to be a simple way to do something like this? What is  
> common recipe for something like this? Should this really be that  
> hard in ruby?

Warning: I didn’t test these…

def clone  
rslt = super # Use the default #clone instead of Myclass.new

```
 instance_variables.each do |member|
   rslt.instance_variable_set( member, instance_variable_get

```

(member).clone )  
end

```
 rslt

```

end

For your particular case you could avoid the loop of course:

def clone  
rslt = super  
rslt.instance\_variable\_set “@var1”, @var1.clone  
rslt.instance\_variable\_set “@arr1”, @arr1.clone  
rslt  
end

Gary W.

---

<div class="post-metadata">

**Author:** ![Shea\_M](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ecccb3/32.png) [@Shea\_M](https://www.ruby-forum.com/u/Shea_M)\
**Post date:** [January 19, 2007, 4:31pm UTC](https://www.ruby-forum.com/t/cloning-object-with-array-members/81288/4 "2007-01-19T16:31:52Z")

</div>

Shea M. wrote:

> ‘cleanest’ way to do this?  
> end  
> rslt.arr1 = @arr1.clone
> 
> ~S

Thanks for all the help. My last attempt at clone turns out to be fine,  
I just forgot to return ‘rslt’. That fixed everything.

~S

---

<div class="post-metadata">

**Author:** ![Shea\_M](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ecccb3/32.png) [@Shea\_M](https://www.ruby-forum.com/u/Shea_M)\
**Post date:** [January 19, 2007, 4:31pm UTC](https://www.ruby-forum.com/t/cloning-object-with-array-members/81288/5 "2007-01-19T16:31:51Z")

</div>

> Hmmm… I’ll try overriding clone, and manually deal with the arrays:
> 
> def clone  
> rslt = super.clone  
> end
> 
> This blows the stack, I believe because all methods are inherited  
> virtually.

The method which must be overriden is initialize\_copy

def initialize\_copy(from)  
@arr1 = from.instance\_eval(’@arr1’).clone  
end

---

<div class="post-metadata">

**Author:** ![Shea\_M](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ecccb3/32.png) [@Shea\_M](https://www.ruby-forum.com/u/Shea_M)\
**Post date:** [September 25, 2007, 10:39pm UTC](https://www.ruby-forum.com/t/cloning-object-with-array-members/81288/6 "2007-09-25T22:39:36Z")

</div>

Shea, you found your answer in the meantime, but I wanted to show you  
what was wrong with your other attempts:

> > a = MyClass.new  
> > b = a.clone
> > 
> > This method leaves ‘b.arr1’ pointing to the same data as a.arr1.

Yes, the default #dup and #clone create a shallow copy.

> > def clone  
> > rslt = super.clone  
> > end
> > 
> > This blows the stack, I believe because all methods are inherited  
> > virtually.

“super” isn’t the same as in Java. super calls the same method of the  
superclass, so what you are doing here is:

temp = super  
rslt = temp.clone

Since temp is an instance of MyClass, you’re calling clone again, which  
gives you and endless recursion. The correct way would have been:

def clone  
super  
end

But this obviously doen’t help you.

> > def clone  
> > rslt = MyClass.new  
> > rslt.var1 = @var1  
> > rslt.arr1 = @arr1.clone  
> > rslt  
> > end
> > 
> > Turns out this does not compute either, as there is no method var1= or  
> > arr1= ! I want to keep var1 private, so can’t go this route either.

The solution to this problem was:

> > def clone  
> > rslt = MyClass.new
> > 
> > ```
> > self.instance_variables.each do |member|
> > rslt.instance_variable_set( member, 
> > 
> > ```
> > 
> > self.instance\_variable\_get(member).clone )  
> > end  
> > end
> > 
> > This fails as the methos do not seem to copy over.

And here, as you’ve noted yourself, you just forgot to return your new  
instance.

Regards,  
Pit

---

<div class="post-metadata">

**Author:** ![Shea\_M](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ecccb3/32.png) [@Shea\_M](https://www.ruby-forum.com/u/Shea_M)\
**Post date:** [September 25, 2007, 10:52pm UTC](https://www.ruby-forum.com/t/cloning-object-with-array-members/81288/7 "2007-09-25T22:52:40Z")

</div>

Alle 22:35, martedì 9 gennaio 2007, Shea M. ha scritto:

> This clone method bombs if any of the instance variables are FixNums,  
> Floats, boolean, etc. Is there a way in my loop to know if an instance  
> variable supports ‘clone’?
> 
> ~S

I don’t know whether there is a way to know in advance if a variable  
supports  
clone, so I’d say: try it. If it works, good. If it doesn’t, it’ll raise  
an  
exception, which you can rescue:

def clone  
rslt = BuildConfig.new

self.instance\_variables.each do |member|  
begin rslt.instance\_variable\_set( member,  
self.instance\_variable\_get(member).clone )  
rescue Exception: rslt.instance\_variable\_set(member,  
self.instance\_variable\_get(member))  
end  
end

return rslt  
end

I’m not an expert, so there may be better ways to do this I don’t know,  
but this should work.

Stefano

---

<div class="post-metadata">

**Author:** ![Shea\_M](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ecccb3/32.png) [@Shea\_M](https://www.ruby-forum.com/u/Shea_M)\
**Post date:** [September 25, 2007, 10:48pm UTC](https://www.ruby-forum.com/t/cloning-object-with-array-members/81288/8 "2007-09-25T22:48:35Z")

</div>

def clone  
rslt = BuildConfig.new

```
 self.instance_variables.each do |member|
       rslt.instance_variable_set( member,
                    self.instance_variable_get(member).clone )
 end

 return rslt

```

end

This clone method bombs if any of the instance variables are FixNums,  
Floats, boolean, etc. Is there a way in my loop to know if an instance  
variable supports ‘clone’?

~S
