Re: Oo.copy

Jacques GARRIGUE (garrigue@kurims.kyoto-u.ac.jp)
Wed, 29 May 1996 10:53:02 +0900

From: Jacques GARRIGUE <garrigue@kurims.kyoto-u.ac.jp>
Date: Wed, 29 May 1996 10:53:02 +0900
Message-Id: <199605290153.KAA16153@orion>
To: caml-list@pauillac.inria.fr
Subject: Re: Oo.copy

>>>>> "Andrew" == Andrew Conway <arc@wildtype.Stanford.EDU> writes:

>> From: Jacques GARRIGUE <garrigue@kurims.kyoto-u.ac.jp>
>>
>>>>>>> ESPERET PHILIPPE <100060.2106@compuserve.com> writes:
>>
>> > I cannot understand how to access a fresh copy of an object with
>> > O'Caml (Oo seems normally to copy only pointers). Thank you if someone
>> > can explain me how to get such a copy (please see below for an example).
>>
>> > [ gives example of a class where a mutable element of the class
>> > (an array) is not copied by OO.copy ]
>>
>> The problem is that your array is shared between the two copies.
>> There are various specific ways to solve it.

Andrew> I think that is a bad feature. I realise it may be unavoidable.

Andrew> In particular, when I read the documentation for OO.copy, I assumed
Andrew> that it was a function that descended the data structure, copying
Andrew> all mutable structures. This seemed like a very useful thing to me
Andrew> (and I wish it was available for any given type, not just classes).

Andrew> I can immagine that this is impractical due to the overhead involved
Andrew> in building specific "deep" copy functions for each data type defined
Andrew> (that could possibly contain a mutable data structure), unless the
Andrew> GC information contains enough of a specification to write a general
Andrew> copy function similar to the general comparison functions. This would perhaps
Andrew> only take one bit per block...saying whether the particular block
Andrew> is mutable or not. On the other hand, I do realise that bits are
expensive.

It's not even clear what should be considered as mutable. For
instance, strings are mutable, but most often you would expect deep
copy to copy them. And what should you do about hashtables, etc...

In fact, there is a way to build a general deep copy, if you don't
care about how expensive it is: use the Obj module (about physical
objects, not Oo), and read C headers.

open Obj

let deep_copy (x : 'a) : 'a =
let copied = ref [] in
let rec copy_obj x =
if is_block x & (tag x < 249 or tag x = 252 or tag x = 254) then
try List.assq x in:!copied
with Not_found ->
let x' = new_block (tag x) (size x) in
for i = 0 to size x - 1 do set_field x' i (field x i) done;
copied := (x,x') :: !copied;
for i = 0 to size x' - 1 do
let y = copy_obj (field x' i) in
if y != field x' i then set_field x' i y
done;
x'
else x
in magic (copy_obj (repr x))

This is quite violent, but should work in most cases. Sharing is
preserved. You can extend it to give a list of objects you want to
leave shared with the original.

>> One is to add an "unsharing" method in the virtual class, which is
>> applied after copying.

Andrew> Ugh!

Didier gave a cleaner way to do it. I didn't read the formal
definition for classes...

Jacques
---------------------------------------------------------------------------
Jacques Garrigue Kyoto University garrigue@kurims.kyoto-u.ac.jp
<A HREF=http://wwwfun.kurims.kyoto-u.ac.jp/~garrigue/>JG</A>