Problems with dup and clone

In the snippet of code below hosts holds a set of class instances for
each host in a monitoring program. There are some special host that are
default entries for unix, windows and other types of systems.

We get the name of the machine to be monitored into $mach and see if we
have an entry for it, if we don’t then we use one of the defaults.

 if ! host then
if type = type_of_host( filename ) then
  host = hosts[mach] =  hosts[ "default-#{type}"].clone
else
  host = hosts[mach] = hosts[ "default"].clone
end
host.name = mach
  end

I have tried both dup and clone to copy the default objects but I always
seem to end up with the original object in host.

The symptom is that when the second machine uses the default entry it
gets the same copy as the first one.

I have printed out host and hosts[ “default-#{type}”]:

#<#Class:0xb7537bc4:0xb73e5a00>
#<#Class:0xb7537bc4:0xb73e599c>

Clearly I’m missing something important!

Russell

Russell F. wrote:

I have tried both dup and clone to copy the default objects but I always
seem to end up with the original object in host.

More investigations reveals that the objects are being at least
partially copied. ‘simple’ variables (strings etc) are copied by arrays
are not.

I have managed to work around this by adding a method fix to the class
which reinitalised the instance arrays to [] and fix’ing the newly
dup’ed instances.

This appears to be a bug in ruby. I’ll see if I can reproduce it in a
small program.

Russell F. wrote:

if type = type_of_host( filename ) then
The symptom is that when the second machine uses the default entry it
Russell


Posted via http://www.ruby-forum.com/.

Not sure if this is any help, but just today I found there is a way to
do a deepcopy
using Marshal

google search yields:
http://cyll.org/blog/tech/2006-05-26-noiwantthedeepcopy.html

but I always
which reinitalised the instance arrays to [] and fix’ing the newly
dup’ed instances.

This appears to be a bug in ruby. I’ll see if I can
reproduce it in a
small program.

As several people have already indicated, Ruby’s clone() and dup()
perform “shallow copy” by design. To achieve deep copy you can use
Marshal:

deep_cloned_object = Marshal.load(Marshal.dump(object))

Alternatively, you can use YAML instead of Marshal. Its serialized
output is human readable.

Best,
Gennady.

On 8/14/06, Russell F. [email protected] wrote:

I have printed out host and hosts[ “default-#{type}”]:

#<#Class:0xb7537bc4:0xb73e5a00>
#<#Class:0xb7537bc4:0xb73e599c>

But those ARE two different instances. The interesting thing is that
the class in both cases seems to be anonymous.

How did you build hosts? You say that it contains different “class
instances”

One way to get such anonymous classes would be something like this:

irb(main):040:0> fd = Foo.dup
=> #Class:0xb7d1404c
irb(main):041:0> fd.new
=> #<#Class:0xb7d1404c:0xb7d11310>
irb(main):042:0> fd.new
=> #<#Class:0xb7d1404c:0xb7d0f074>
irb(main):043:0> fd.new.equal?(fd.new)
=> false

Note that the two instances have the same oid for their class, (which
is the copy of the Foo class), but different oids of their own.

Rick DeNatale

IPMS/USA Region 12 Coordinator
http://ipmsr12.denhaven2.com/

Visit the Project Mercury Wiki Site
http://www.mercuryspacecraft.com/

Russell F. wrote:

Russell F. wrote:

I have tried both dup and clone to copy the default objects but I always
seem to end up with the original object in host.

More investigations reveals that the objects are being at least
partially copied. ‘simple’ variables (strings etc) are copied by arrays
are not.

I have managed to work around this by adding a method fix to the class
which reinitalised the instance arrays to [] and fix’ing the newly
dup’ed instances.

This appears to be a bug in ruby. I’ll see if I can reproduce it in a
small program.

OK, not a bug but a feature. My copy of the pickaxe was at home and I
now understand that dup and clone only do shallow copies. I’m wondering
if I can use initialize_copy to copy the arrays that I need – it is
described as a call back – do I just define a method of that name and
it will be called on copy? I’ll just have to suck and see!

To Rick who was curious about the anonymous classes. Yes they are
anonymous, this program is a log scanner and I generate a class for each
host in the config file with its own scanner and alert routine to
process logs. I read the config file then generate the scanner
routines on the fly using eval. I’m not sure why I made them anonymous
they don’t have to be and I may well change it. The code is in svn on
rubyforge in the selms project. I’ll be updating it soon and doing the
first beta release in a week or so. I need to do a short web page
before I get to that point - bloody documentations :wink:

Thanks to those who responded to my post :slight_smile: I did google this but
clearly not very effectively!

Russell

On 8/15/06, Russell F. [email protected] wrote:

Russell F. wrote:

To Rick who was curious about the anonymous classes. Yes they are
anonymous,

My point wasn’t so much that the classes were anonymous, but that
those instances realy WERE distinct objects, so as far as I can see,
you don’t have a problem with dup or clone.


Rick DeNatale

http://talklikeaduck.denhaven2.com/

Russell F. wrote:

OK, not a bug but a feature. My copy of the pickaxe was at home and I
now understand that dup and clone only do shallow copies. I’m wondering
if I can use initialize_copy to copy the arrays that I need – it is
described as a call back – do I just define a method of that name and
it will be called on copy? I’ll just have to suck and see!

final word on this one. Yes initialize_copy does the trick. Iv’e
renamed fix to initialize_copy and taken the calls to it out of the code
and it all works as it should.

Cheers and thanks,

Russell

On Wednesday, August 16, 2006, at 3:34 AM, Rick DeNatale wrote:

the class in both cases seems to be anonymous.
irb(main):042:0> fd.new
http://ipmsr12.denhaven2.com/

Visit the Project Mercury Wiki Site
http://www.mercuryspacecraft.com/

As I recently discovered, arrays don’t get deep copied with dup or
clone. My guess is that ruby stores a pointer to an array internally
and that is what gets copied when you clone the object. So both
copies point to the original array.

_Kevin
www.sciwerks.com