[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

deepcopy via eval

OliverMarchand

4/11/2006 8:18:00 AM

Dear Ruby people,

I spent quite a while yesterday reviewing the discussions on deep
copying in ruby. An approach that I have not seen anywhere is to use a
combination of eval and inspect to deep copy an object. The essence of
the idea is:

obj_copy = eval(obj.inspect)

The standard approach is via Marshalling, but it doesn't really work:
e.g.

[[1,2,3]]*3

is a typical array, which does not contain three independent arrays,
but three pointers to the same array [1,2,3]. When Marshalling is
applied to copy this object the internal structure is preserved, which
may be a desirable feature or not. BTW: is there a good way to display
(a) that exact internal structure, (b) the contents of a Marshal
serialize string?

Now with the above eval method you get a real deep copy of the
123array, but the method is (a) slow and (b) does not work for objects
which do not return a string that can be used for instantiation of that
exact same object upon receiving inspect (which is the regular case).
But it works for simple combinations of strings, hashes, arrasy, floats
and ints, etc.

Now to make it more usable, I have combined the two in a very simple
module. One could also mix these into classes to make them accessible
via a method. The code below works for more things than the simple
Marshal version, but the behaviour is far from "under perfect control",
thus I hesitate to continue with this module. Are there comments and/or
better version and/or extensions out there?

---
module Deepcopy

def Deepcopy.bymarshal(obj)
return Marshal.load(Marshal.dump(obj))
end

def Deepcopy.byeval(obj)
if obj==nil
return nil
else
begin
e = eval(obj.inspect)
rescue Exception
end
e = Deepcopy.bymarshal(obj) if e == nil
return e
end
end

end
---

ciao,
Oliver

--
Oliver Marchand
Wunderlistr. 45
CH-8037 Zürich
Mobile: +41 78 8032102
Email (private): oliver.marchand@gmail.com
Email (work): oliver.marchand@meteoswiss.ch

6 Answers

OliverMarchand

4/11/2006 10:02:00 AM

0

I apologize for the multiple posts of this message. Google groups
assured me several times that due to server timeout the message was not
sent yet and the copies appeared hours after the last message was
finally sent "correctly".

oh, well,
Oliver

Robert Klemme

4/11/2006 11:56:00 AM

0


IMHO this is not a good idea for several reasons, the most serious
probably being:

- Marshal works for far more object types than your approach with
inspect and eval

- even in a deep copy you want the structure preserved, i.e. not
suddenly get two objects where there was just one on the input side

- eval might not be accessible (security constraints)

Kind regards

robert

OliverMarchand

4/12/2006 9:02:00 AM

0

Dear Robert,

I mostly agree with your criticism, thanks for the input.

Nevertheless I have pursuied the approach a little bit and added a
deepcopy method to the class Object, using the approach described
above. I only want to mention that hen one probably needs to reserve
another additional method, which returns the "instantiation string". I
consider that undesirable.

cheers,
Oliver

Stefano Taschini

4/12/2006 9:40:00 AM

0

Ufpasse!

Your method does not work for floats either, as #inspect dumps floats
with not nearly enough digits.

x = 1.9 - 0.9
#=> 1.0
x.inspect
#=> "1.0"
eval(x.inspect) == x
#=> false

The reason can be seen with 17 digits:

"%.17f" % x
#=> "0.99999999999999989"

Ciao,
Stefano

P.S.
In Python, the two functions repr() and str() are equivalent to Ruby's
#inspect and #to_s. For floats repr() includes enough digits to
reconstruct exactly the value of the floating-point number. This makes
life slightly easier for experts, but can be extremely confusing for
the casual programmer: one of the Python FAQs is about why 1.9-0.9
yields 0.99999999999999989.

OliverMarchand

4/12/2006 9:50:00 AM

0

Yes, you are right. repr is exactly the function that I added for that
pupose.

I see that the whole eval approach for deep copying is fairly useless.

Now I am wondering what the best solution to convert arrays like
x = [[1,2,3]]*3
into an equivalent structure, which changes only the first element upon

x[0] = ...whatever...


???
Oliver

Robert Klemme

4/12/2006 10:47:00 AM

0

OliverMarchand wrote:
> Yes, you are right. repr is exactly the function that I added for that
> pupose.
>
> I see that the whole eval approach for deep copying is fairly useless.
>
> Now I am wondering what the best solution to convert arrays like
> x = [[1,2,3]]*3
> into an equivalent structure, which changes only the first element upon
>
> x[0] = ...whatever...

x.map {|i| i.dup}

robert