Persisting and loading objects trhough Marshal problem

Hello people. Today I’ve found a bug in my source code, been around for
a while until I realized of the problem, here is a bit of code which
represent it:

-----------------------------------

class A
def initialize
@var_a = 50
end
end

class B
attr_accessor :var_b
def initialize(value)
@var_b = value
end
end

a = A.new
b = B.new(a)

#I ‘marshal’ both of the variables
#Then close the app, open it and load again their state, so I expect
#that the next snippet is true:

p b.var_b.==(a)
#=> false

#They are differents objects and I don’t need that.

-----------------------------------

So how do you think that I can resolve this problem? Been thinking for
a solution but I’m not sure about…
I’ll appreciate your help, thank you very much. Damián.

how do you marshal them? if you marshal them in ONE step it can solve
your circle

Good question. See, I marshal them in differents times. Because I don’t
have to persist lot of information I don’t use any database like MySQL,
I just save the object in binary files(by marshaling). The application
have a GUI, so when a user do some thing certain object is persisted,
that object is pointing to other objects, like the example of @var_b.
The problem is that when I regenerate the objects, the shown above
happen.
When in some part of the source code I have to compare in the way above
the are not equals:

b.var_b.inspect
#=> <A:0x0145A4>
a.inspect
#=> <A:0x457D78>

They are not the same, perhaps(meaby an obvious thing) because Marshal
reconstruct the object just by looking their atributes saved but Marshal
doesn’t bother about create the same object that another that will be
created with the same attributes. Am I right?

I have to add that I persist them in differents files. I’ve
realized(meaby) what you mean: You mean persist both object in ONE step
like put them into an #Array and then persist the Array? Well that meaby
can solve the problem, but the meaning of persist the object in
different steps and differents files is that isn’t the same persist 1K
of information(one object) than persist the whole model, like 50 objects
at the same time. I didn’t see the sense of that because the application
is just changing one object when the user do a certain movement in the
GUI, not the 50, so I didn’t see the sense in save the whole model.

On Wed, Mar 6, 2013 at 4:58 PM, Damin M. Gonzlez [email protected]
wrote:

b.var_b.inspect
#=> <A:0x0145A4>
a.inspect
#=> <A:0x457D78>

They are not the same, perhaps(meaby an obvious thing) because Marshal
reconstruct the object just by looking their atributes saved but Marshal
doesn’t bother about create the same object that another that will be
created with the same attributes. Am I right?

Marshal retains an idea of identity only during one write operation.
So it will reconstruct graphs properly if you ensure all interesting
instances are referenced from a single instance.

As Hans said: do it in one step for example by placing both in an Array:

irb(main):016:0> x, y = Marshal.load(Marshal.dump([a,b]))
=> [#<A:0x802ba284 @var_a=50>, #<B:0x802ba248 @var_b=#<A:0x802ba284
@var_a=50>>]
irb(main):017:0> x.equal? y.var_b
=> true

In your case it would also be sufficient to only marshal b because
that references a already and there is an easy way to access it after
deserialization.

Kind regards

robert

Marshal retains an idea of identity only during one write operation.
So it will reconstruct graphs properly if you ensure all interesting
instances are referenced from a single instance.

I can now clearly see what you say.

As Hans said: do it in one step for example by placing both in an Array:

irb(main):016:0> x, y = Marshal.load(Marshal.dump([a,b]))
=> [#<A:0x802ba284 @var_a=50>, #<B:0x802ba248 @var_b=#<A:0x802ba284
@var_a=50>>]
irb(main):017:0> x.equal? y.var_b
=> true

Yes, it’s what I say above

In your case it would also be sufficient to only marshal b because
that references a already and there is an easy way to access it after
deserialization.

I understand what you say, but my model is far more complex, I have
many objects with atributtes pointing to anothers objects from
differents clases, it’s not so simple. At now the only way that I see
is: in some way try to reconstruct the objects manually, for example,
many of my classes will have only one instance at time in the model, so
I can do something like this(referencing the above example):

---------------------------------*-

#supposing that before I’ve loaded the state of ::A1 which is the state
#of the above a variable

#monkeypatch
class B
def marshal_dump
[@var_b]
end

#Note: I have all the only-one-instance-per-class pointed by a
#constant in the main scope(don’t know if this is a good way just
#implemented in that way))
def marshal_load(attributes)
@var_b = (if attributes[0].is_a?(A) then ::A1 else attributes[0] end)
end
end

-----------------------------------*-

Do you think that exist a better and faster way than this to treat with
the problem? I’ll appreciate your help, thanks.