From: Robert Klemme Date: 2005-09-06T16:48:51+09:00 Subject: Re: Efficient Object Reconstruction? Austin Ziegler wrote: > I have a problem, and it's been bugging me for a while, so I thought > that I'd ask people that know a lot more about the internals of Ruby > than I do. > > In PDF::Writer, I have a complex object graph. Its complexity is > mostly caused by the fact that all objects must know their parent > object. Maybe something like: > > foo#35 > bar#36 (@parent = foo#35, ...) > baz#37 (@parent = foo#35, ...) > > When this graph gets roundtripped through Marshal, I might have: > > foo#38 > bar#39 (@parent = foo#35, ...) > baz#40 (@parent = foo#35, ...) I don't think so. Since the whole graph is copied foo#35 is copied and references are adjusted so you end up with parent = foo#38 - regardless whether you copy the root object or any other object (Marshal cannot know what the root / parent object is anyway): 09:33:39 [ruby]: ruby mar-ref.rb 134688280 134688268 134688148 134688100 false false 134687860 134687896 false false 09:34:41 [ruby]: cat mar-ref.rb T = Struct.new(:ref) a = [] a << T.new(a) print a.object_id, " ", a[0].object_id, "\n" b = Marshal.load(Marshal.dump(a)) print b.object_id, " ", b[0].object_id, "\n" print b.object_id == a.object_id, " ", b[0].object_id == a[0].object_id, "\n" c = Marshal.load(Marshal.dump(a[0])) print c.ref.object_id, " ", c.object_id, "\n" print c.ref.object_id == a.object_id, " ", c.object_id == a[0].object_id, "\n" > This means that there are now "odd" copies of at least the parent > (foo#35) around. This is something that *does* happen when > Transaction::Simple is called. Now, if I then add something else: > > foo#38 > bar#39 (@parent = foo#35, ...) > baz#40 (@parent = foo#35, ...) > bom#41 (@parent = foo#38, ...) > > Obviously, this not only gets silly after a while, but it gets pretty > inefficient. This might be a problem of Transaction::Simple (disclaimer, I never used it). You probably have to copy the complete graph every time and discard the old one. > I want to fix Transaction::Simple so that the object graph is > *properly* reconstructed. That is, if I Marshal.dump the foo with > object ID 35, I don't mind if it's reconstituted as #38, but I want > "old" references to #35 reconstructed as references to #38. > > How can I do that? Preferably, how can I do that without crawling the > object graph -- which would be extremely inefficient? I don't think there is an easy solution that allows to write an instance twice to the stream and adjusting references on checkout other than writing it twice in one Marshal.dump step. The easiest might be to create a mapping on your own, store this mapping and adjust it after deserializing. Kind regards robert