Marshalling cyclic data structures

N

Nathan Weston

I need to marshal and load cyclic data structures, and I need to write
custom marshalling routines because not all the fields of these
structures can be saved.

The default marshalling routines work fine on cyclic data, but when I
write my own, they go into an infinite loop.

Here is some simplified code that demonstrates the problem:

class Cons
def Cons._load(str)
hash = Marshal.load(str)
c = Cons.new()
c.value = hash["value"]
c.rest = hash["rest"]

return c
end

def _dump(depth)
return Marshal.dump({"value" => @value, "rest" => @rest})
end

attr_accessor :value, :rest
end

first = Cons.new
second = Cons.new

first.rest = second
second.rest = first

Marshal.dump(first)


This will hang on the call to Marshal.dump. Is the a simple way to
make this work?

Nathan
 
T

ts

N> I need to marshal and load cyclic data structures, and I need to write
N> custom marshalling routines because not all the fields of these
N> structures can be saved.

If you have a recent version of ruby you can use #marshal_load and
#marshal_dump, something like

svg% cat b.rb
#!/usr/bin/ruby -v
class Cons
def marshal_load(hash)
@value = hash["value"]
@rest = hash["rest"]
end

def marshal_dump
{"value" => @value, "rest" => @rest}
end

attr_accessor :value, :rest
end

first = Cons.new
first.value = 12
second = Cons.new
second.value = 24

first.rest = second
second.rest = first

c = Marshal.load(Marshal.dump(first))

p first
p c
svg%

svg% b.rb
ruby 1.8.0 (2003-08-04) [i686-linux]
#<Cons:0x400999e4 @value=12, @rest=#<Cons:0x400998cc @value=24, @rest=#<Cons:0x400999e4 ...>>>
#<Cons:0x400997f0 @value=12, @rest=#<Cons:0x400997a0 @value=24, @rest=#<Cons:0x400997f0 ...>>>
svg%
 
D

daz

ts said:
N>[...] not all the fields of these structures can be saved.

Playing with your code example, Guy, I supplied a proc as an
example of a structure which Marshal doesn't serialize:

second.value = proc {'X'}

which produces ...

C:/TEMP/rb7005.TMP:31:in `dump': class Proc needs to have instance method `marshal_dump' (TypeError)

OK. After extending Proc, this code ...

xxx% cat b.rb
#!/usr/bin/ruby -v
class Cons
def marshal_load(hash)
@value = hash["value"]
@rest = hash["rest"]
end

def marshal_dump
{"value" => @value, "rest" => @rest}
end

attr_accessor :value, :rest
end

class Proc
def marshal_load(dummy)
nil
end
def marshal_dump
""
end
end

first = Cons.new
first.value = 12
second = Cons.new
second.value = proc {'X'}

first.rest = second
second.rest = first

c = Marshal.load(Marshal.dump(first))

p first
p c
xxx%


.... produces ...

C:/TEMP/rb7005.TMP:32:in `load': allocator undefined for Proc (NoMethodError)

Now I don't understand what it's asking for.

<ri>
----------------------------------------------------------------- Class#allocate
aClass.allocate -> anObject
--------------------------------------------------------------------------------
Allocates space for a new object of aClass's class. The returned object
must be an instance of aClass.
</ri>

(Blindly adding Proc#allocate - new to me - didn't change the error message.)

[class Proc]
def allocate
Proc.new {nil}
end
[end]


Thanks for any illumination,


daz
 
T

ts

d> C:/TEMP/rb7005.TMP:32:in `load': allocator undefined for Proc
^^^^^^^^^

it want an allocator which can be defined only at C level (if I'm right).

d> (Blindly adding Proc#allocate - new to me - didn't change the error
d> message.)

Normally this is Proc::allocate (singleton method) but this is not really
the same, for example

svg% cat b.rb
#!/usr/bin/ruby

class A
def self.allocate
print "allocate "
super
end

def self.new
print "new "
super
end
end

p A.allocate
p A.new
svg%

svg% b.rb
allocate #<A:0x40099e6c>
new #<A:0x40099e30>
svg%

the first time is call A::allocate which call Object::allocate which
internally call an allocator

the second time the method A::new call internally the allocator and not
the method A::allocate

In your case, Proc has undefined its allocator
 
T

ts

t> the first time is call A::allocate which call Object::allocate which
^^^^^^^^^^^^^^^^
well in reality this is Class#allocate

sorry,

t> internally call an allocator
 
N

Nathan Weston

Thanks, that was exactly what I needed.

Nathan

ts said:
N> I need to marshal and load cyclic data structures, and I need to write
N> custom marshalling routines because not all the fields of these
N> structures can be saved.

If you have a recent version of ruby you can use #marshal_load and
#marshal_dump, something like

svg% cat b.rb
#!/usr/bin/ruby -v
class Cons
def marshal_load(hash)
@value = hash["value"]
@rest = hash["rest"]
end

def marshal_dump
{"value" => @value, "rest" => @rest}
end

attr_accessor :value, :rest
end

first = Cons.new
first.value = 12
second = Cons.new
second.value = 24

first.rest = second
second.rest = first

c = Marshal.load(Marshal.dump(first))

p first
p c
svg%

svg% b.rb
ruby 1.8.0 (2003-08-04) [i686-linux]
#<Cons:0x400999e4 @value=12, @rest=#<Cons:0x400998cc @value=24, @rest=#<Cons:0x400999e4 ...>>>
#<Cons:0x400997f0 @value=12, @rest=#<Cons:0x400997a0 @value=24, @rest=#<Cons:0x400997f0 ...>>>
svg%
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top