Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Can I serialize an object and have it remember it's type?

by tphyahoo (Vicar)
on Jul 21, 2005 at 13:13 UTC ( #476806=perlquestion: print w/ replies, xml ) Need Help??
tphyahoo has asked for the wisdom of the Perl Monks concerning the following question:

Is there a way to serialize an object in such a way that when I retrieve it later it remembers what "type" it was blessed into?

I tried to do this with DBM::Deep, but as you see, no dice.

#test.pl use warnings; use strict; use Data::Dumper; use DBM::Deep; use LWP::UserAgent; use Test::More qw(no_plan); my $hash = DBM::Deep->new("foo.db"); my $user_agent = LWP::UserAgent->new; isa_ok($user_agent, 'LWP::UserAgent'); #passes $hash->{my_user_agent} = $user_agent; my $user_agent2 = $hash->{my_user_agent}; isa_ok($user_agent2, 'LWP::UserAgent');#fails print Dumper($user_agent2);
Output of test.pl 2>>test.pl and then test.pl >>test.pl
Failed test (read.pl at line 15) The object isn't a 'LWP::UserAgent' it's a 'DBM::Deep' Looks like you failed 1 tests of 2. ok 1 - The object isa LWP::UserAgent not ok 2 - The object isa LWP::UserAgent $VAR1 = bless( { 'requests_redirectable' => bless( [ 'GET', 'HEAD' ], 'DBM::Deep' ), 'max_redirect' => '7', 'proxy' => undef, 'parse_head' => '1', 'use_eval' => '1', 'timeout' => '180', 'protocols_allowed' => undef, 'agent' => 'libwww-perl/5.79', 'protocols_forbidden' => undef, 'no_proxy' => bless( [], 'DBM::Deep' ), 'from' => undef, 'max_size' => undef }, 'DBM::Deep' ); 1..2
This is sort of a followup to How's mldbm with concurrency?, where I was doing serialization with mldbm. I wound up switching to DBM::Deep on merlyn's advice, but that was before it occurred to me I might be checking for what kind of object I pulled out.

**********

UPDATE: I think chromatic's Object Serialization Basics is a good place to learn how to do this.

Comment on Can I serialize an object and have it remember it's type?
Select or Download Code
Re: Can I serialize an object and have it remember it's type?
by tlm (Prior) on Jul 21, 2005 at 13:25 UTC

    I'm not familiar with DBM::Deep, but don't you need to eval the serialization (string) to recover the desired object?

    FWIW, I serialize objects with Storable all the time, so it's definitely possible.

    the lowliest monk

      Evaling didn't work in this case, but thanks for your comment. I didn't realize that was how serialization was supposed to work, but now this all makes more sense. I'm going to try serializing and evaling with Storable now.
      **********
      Update, yep, this works.
      use strict; use warnings; use Storable qw(store retrieve freeze thaw dclone); use LWP::UserAgent; use Test::More qw(no_plan); my $user_agent = LWP::UserAgent->new; isa_ok($user_agent, 'LWP::UserAgent'); store($user_agent, 'myuseragent') or die "Can't store useragent!\n"; my $user_agent2 = retrieve('myuseragent'); isa_ok($user_agent2, 'LWP::UserAgent');

        Evaling didn't work in this case...

        How exactly did it fail? Does the error go away if you precede the eval'ing with my $VAR1;?

        I'm going to try serializing and evaling with Storable now.

        With Storable explicit eval'ing is not required; just use its store and retrieve functions.

        Update: Gah! I entirely missed that in the serialization string the blessing had the wrong class. As tphyahoo kindly points out, no amount of eval-ing will fix this.

        the lowliest monk

        Be forewarned - Storable does not provide forward/backward compatability. That is, if you upgrade your perl, there is a significant chance that all your stored objects will be unretrievable. If you switch platforms, it's almost guaranteed (use nstore - that may help).

        At least, that was my experience with Storable, oh so many years ago. I'd be happy to hear that has changed.

Re: Can I serialize an object and have it remember it's type?
by rinceWind (Monsignor) on Jul 21, 2005 at 13:46 UTC

    If you want to serialize in a human readable form, try YAML. Serialization of objects, be it with storable, Data::Dumper or YAML, will preserve the blessing, hence blessed objects are returned when you load them back.

    Bear it in mind that loading an object twice will produce two different objects but with the same contents.

    --

    Oh Lord, won’t you burn me a Knoppix CD ?
    My friends all rate Windows, I must disagree.
    Your powers of persuasion will set them all free,
    So oh Lord, won’t you burn me a Knoppix CD ?
    (Missquoting Janis Joplin)

      Note that "serializing" objects using Data::Dumper or YAML only work because they break encapsulation, and assume something about their implementation - for instance, that objects are implemented using a reference to a hash, and that the entire state of the object depends only on the content of said hash (or reference to an array, or scalar).

      Serializing fly weigth objects or inside out objects will not work using Data::Dumper or YAML. You'll need to write your serialize/deserialize routines in (all) your classes.

        Minor correction: object state serialization works for any blessed type in Perl, not just references to hashes.
        package XX; sub new { bless([1,2,3],__PACKAGE__) } package YY; sub new { $abc="abc"; bless(\$abc,__PACKAGE__) } package ZZ; sub new { $ott=123; bless(\$ott,__PACKAGE__) } package main; use Data::Dumper; print +(Dumper(new XX)); print +(Dumper(new YY)); print +(Dumper(new ZZ)); __OUTPUT__ $VAR1 = bless( [ 1, 2, 3 ], 'XX' ); $VAR1 = bless( do{\(my $o = 'abc')}, 'YY' ); $VAR1 = bless( do{\(my $o = 123)}, 'ZZ' );
        You are right that state serialization only works when the state is entirely referenced through that blessed value. You could even say that it's breaking package encapsulation.

        But state serialization is, as the name implies, writing the state of the object, not the state of the package which manages the object. If you want to implement a new object model on top of the one Perl has got already, including flyweight or inside-out, then your new object model will have to be responsible for any serialization tasks. Unfortunately, that means that packages with non-native object models must document that they need special handling for serialization.

        --
        [ e d @ h a l l e y . c c ]

Re: Can I serialize an object and have it remember it's type?
by tphyahoo (Vicar) on Jul 27, 2005 at 09:18 UTC
    Okay, I got this working with
    #test.pl use warnings; use strict; use DBM::Deep; use Data::Dumper; use LWP::UserAgent; use Test::More qw(no_plan); my $hash = DBM::Deep->new("foo.db"); my $user_agent = LWP::UserAgent->new; $Data::Dumper::Terse=1; my $user_agent_dumped = Dumper($user_agent); $hash->{ua_1} = $user_agent_dumped; my $user_agent_recreated = eval ( $hash->{ua_1} ); isa_ok($user_agent_recreated,'LWP::UserAgent'); #passes
    Thanks to the monks who helped me with my followup at Getting back $object from eval(Dumper($object))

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://476806]
Approved by Limbic~Region
Front-paged by Old_Gray_Bear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (10)
As of 2014-12-18 10:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (48 votes), past polls