"Anonymous classes or modules", what are? (Marshaling)

I'm trying to find out if is possible to serialize a class object, with
their own instance variables, something like this:

class Foo
  @x = 10
  @y = 20
end

Then I went to Dave Thomas book: Programming Ruby 1.9 to the section
which talk about Marshal. It say literaly:

"Some objects cannot be dumped: if the objects to be dumped include
bindings, procedure or method objects, instances of class IO, or
singleton objects, or if you try to dump anonymous classes or modules, a
TypeError will be raised."

So obvious Foo is not a singleton object, is a class object. I've tried
to Marshal this class in the common way and succed, no TypeError arised.
But when I restore, no clue about his own instance variables. I wonder
what does mean Dave when he say "anonymous classes or modules"...
I've opened a topic short time ago related with this, asking about
marshaling classes and his class variables, I surrendered trying to save
classes with his class variables but what about his own instance
variables, It is not a common object? I just can't? What is the option
to serialize this kind of data? Do I have to appeal to metaprogramming?
Thank you guys.

···

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

Damián M. González писал 16.09.2012 02:49:

I'm trying to find out if is possible to serialize a class object, with
their own instance variables, something like this:

class Foo
  @x = 10
  @y = 20
end

Then I went to Dave Thomas book: Programming Ruby 1.9 to the section
which talk about Marshal. It say literaly:

"Some objects cannot be dumped: if the objects to be dumped include
bindings, procedure or method objects, instances of class IO, or
singleton objects, or if you try to dump anonymous classes or modules, a
TypeError will be raised."

So obvious Foo is not a singleton object, is a class object. I've tried
to Marshal this class in the common way and succed, no TypeError arised.
But when I restore, no clue about his own instance variables. I wonder
what does mean Dave when he say "anonymous classes or modules"...
I've opened a topic short time ago related with this, asking about
marshaling classes and his class variables, I surrendered trying to save
classes with his class variables but what about his own instance
variables, It is not a common object? I just can't? What is the option
to serialize this kind of data? Do I have to appeal to metaprogramming?
Thank you guys.

Ruby does not support serializing code. At all. If you serialize something
that includes methods, these methods will not be written to disk.

In other words, you cannot meaningfully serialize classes. When you serialize
a Class instance, only its name gets written. See:
irb > class Klass; @x = 0; end
  => 0
irb > Marshal.dump Klass
  => "\x04\bc\nKlass"
irb > Object.send :remove_const, :Klass
  => A
irb > Klass = 0
  => 0
irb > Marshal.load "\x04\bc\nKlass"
TypeError: Klass does not refer to class/module
         from (irb):10:in `load'
         from (irb):10
         from /home/whitequark/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `<main>'

Also, as the name is used to find a class, you cannot meaningfully serialize
instances of anonymous classes either. see:
irb > k = Class.new
  => #<Class:0x0000000085ea80>
irb > Marshal.dump k.new
TypeError: can't dump anonymous class #<Class:0x0000000085ea80>
         from (irb):13:in `dump'
         from (irb):13
         from /home/whitequark/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `<main>'

I'm not sure as what was mentioned in the book as I don't have it, but I guess
that it was only talking about _instances_ of anonymous classes. You don't often
need to serialize classes themselves, and, as I've mentioned, you cannot serialize
code, be that closures or methods. Objects with singleton methods will have those
singleton methods lost:
irb > obj = Object.new
  => #<Object:0x000000008833a8>
irb > def obj.bark
irb > puts "Howl!"
irb > end
  => nil
irb > serial = Marshal.dump(obj)
TypeError: singleton can't be dumped
         from (irb):18:in `dump'
         from (irb):18
         from /home/whitequark/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `<main>'

···

--
   WBR, Peter Zotov.

Damián M. González wrote in post #1076192:

"Some objects cannot be dumped: if the objects to be dumped include
bindings, procedure or method objects, instances of class IO, or
singleton objects, or if you try to dump anonymous classes or modules, a
TypeError will be raised."

Here are examples of each of these in turn, presented as a member of a
vanilla Hash object. They all fail.

Marshal.dump("foo" => binding)
Marshal.dump("foo" => Proc.new { 0 })
Marshal.dump("foo" => method(:puts))
Marshal.dump("foo" => File.open("/etc/passwd"))

a = "bar"
def a.baz; 0; end
Marshal.dump("foo" =>a)

Marshal.dump("foo" => Class.new)
Marshal.dump("foo" => Module.new)

So obvious Foo is not a singleton object, is a class object. I've tried
to Marshal this class in the common way and succed, no TypeError arised.
But when I restore, no clue about his own instance variables.

Correct, for more info see Marshaling classes - Ruby - Ruby-Forum

I wonder
what does mean Dave when he say "anonymous classes or modules"...

A class which is not assigned to a constant.

# an anonymous class
k = Class.new
p k # => #<Class:0x10640d5d8>

But there is special voodoo the first time you do assign it to a
constant.

Foo = k
p k # => Foo

The class "knows" that its name is Foo. Normally, objects don't know
what variables and/or constants reference them.

I've opened a topic short time ago related with this, asking about
marshaling classes and his class variables, I surrendered trying to save
classes with his class variables but what about his own instance
variables, It is not a common object?

It is, but this is a special case.

{"foo" => String, "bar" => Array}
is serialised as just references to the class named "String" and "Array"

If it worked the way you wanted, then instead of serializing the name it
would have to serialize everything needed to reconstruct the classes
"String" and "Array" - including the methods.

So what we gain is the ability to have objects which contain references
to (named) classes, which is useful, without being able to serialize the
classes themselves.

···

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

Brian Candler wrote in post #1076224:

It is, but this is a special case.

{"foo" => String, "bar" => Array}
is serialised as just references to the class named "String" and "Array"

If it worked the way you wanted, then instead of serializing the name it
would have to serialize everything needed to reconstruct the classes
"String" and "Array" - including the methods.

So what we gain is the ability to have objects which contain references
to (named) classes, which is useful, without being able to serialize the
classes themselves.

Can you give me a short example?

···

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

Peter Zotov wrote in post #1076193:

I'm not sure as what was mentioned in the book as I don't have it, but
I guess
that it was only talking about _instances_ of anonymous classes. You
don't often
need to serialize classes themselves, and, as I've mentioned, you
cannot serialize
code, be that closures or methods. Objects with singleton methods will
have those
singleton methods lost:
irb > obj = Object.new
  => #<Object:0x000000008833a8>
irb > def obj.bark
irb > puts "Howl!"
irb > end
  => nil
irb > serial = Marshal.dump(obj)
TypeError: singleton can't be dumped
         from (irb):18:in `dump'
         from (irb):18
         from /home/whitequark/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in
`<main>'

Is not code what I'm trying to serialize just the state of a class, of
the class object itself, so when the program start it require all the
files needed, included the file which have the class definition, let
say:

#encoding: utf-8
class Foo
  @re = 5
  def initialize(nickname)
    @nickname = nickname
  end
  def self.change_re(n)
    @re = n
  end
  def self.get_re
    @re
  end
end

Then I want to "refresh" the state of this object, the class object.
Let's suppose that when the program was closed, @re was 56, so I want to
"start" in some way, with this variable settled to 56, not 5. I'm clear
explaining? That is just what I need to do, if you can give me a trick
about what's the best way to save this state and restore it I'll be very
thankfull. :slight_smile:

···

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

Damián M. González wrote in post #1076236:

Brian Candler wrote in post #1076224:

It is, but this is a special case.

{"foo" => String, "bar" => Array}
is serialised as just references to the class named "String" and "Array"

If it worked the way you wanted, then instead of serializing the name it
would have to serialize everything needed to reconstruct the classes
"String" and "Array" - including the methods.

So what we gain is the ability to have objects which contain references
to (named) classes, which is useful, without being able to serialize the
classes themselves.

Can you give me a short example?

Any object which includes a Class in an instance variable. I dunno:

class Factory
  def initialize(klass)
    @klass = klass
  end
  def make(*args)
    @klass.new(*args)
  end
end

class Foo
  class <<self; attr_accessor :count; end
  @count = 1
end

f = Factory.new(Foo)
f.make
p Marshal.dump(f)

Now I can happily Marshal.dump(f), even though it contains a reference
to a class (Foo). When I reload the object later, it will still contain
a reference to class Foo. However no attempt is made to restore the
state of Foo itself; that would be an unwanted side-effect, to have the
current class Foo's state changed to how it was at the time when f was
serialized.

The alternative would be to return an anonymous class with the state of
Foo at the time when f was serialized. However that's not an accurate
representation of f (it wasn't pointing to an anonymous class, it was
pointing to Foo). Moreover, we can't serialise anonymous classes anyway,
because that would mean serializing all the methods of that class.

···

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

The alternative would be to return an anonymous class with the state of
Foo at the time when f was serialized. However that's not an accurate
representation of f (it wasn't pointing to an anonymous class, it was
pointing to Foo). Moreover, we can't serialise anonymous classes anyway,
because that would mean serializing all the methods of that class.

Correct me if I'm wrong: the only way that I see to save the state of a
class object(like Foo in your example with his variable @count), is
appeal to some methods that save the current state and then load it
again when the programm start, something like this:

···

######################################################

class Foo
  @x = 1
  class << self
    attr_accessor :x
    def save_state
      a = Object.new
      a.instance_eval do
        @x = Foo.x
      end
      File.open('Foo_state.mrs', 'w+') do |f|
        Marshal.dump(a, f)
      end
    end
    def load_state
      b = Marshal.load(File.open('Foo_state.mrs').read)
      Foo.x = b.instance_variable_get(:@x)
    end
  end
end

if File.exist?('Foo_state.mrs') then Foo.load_state end

########################################################

#Start the program for the first time
Foo.x
#=> 1
Foo.x = 5
#=> 5
Foo.save_state
#=> #<File:Foo_state.mrs (closed)>
#Here I close the program....

#Then I start it again
Foo.x
#=> 5
#Was correctly saved and loaded

I'll wait for your answers :slight_smile:

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