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.

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

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

···

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

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?

···

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

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

···

On Wed, Mar 6, 2013 at 4:58 PM, Damián M. González <lists@ruby-forum.com> wrote:

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?

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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.

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