cloning object with array members

S

Shea Martin

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
 
D

dblack

Hi --

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.

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

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 
G

gwtmp01

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 Wright
 
O

Olivier

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
 
S

Shea Martin

Shea said:
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


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
 
P

Pit Capitain

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

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

"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.

The solution to this problem was:

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

Regards,
Pit
 
S

Shea Martin

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
 
S

Stefano Crocco

Alle 22:35, marted=EC 9 gennaio 2007, Shea Martin ha scritto:
def clone
rslt =3D 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

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

def clone
rslt =3D BuildConfig.new

self.instance_variables.each do |member|
begin rslt.instance_variable_set( member, self.instance_variable_get(me=
mber).clone )
rescue Exception: rslt.instance_variable_set(member, self.instance_vari=
able_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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top