in reply to Basic STORABLE_attach scenario doesn't work

You are correct. that line should be:     my ($num, $txt) = ($serialized =~ /(\d+)(\w+)/);

The regex needs to be in a list context to return the two values.

Nice catch but it answer if still wrong. The output now looks like

Attach num: (2) text: (Two) class: (Number) self: (Number=HASH(0x12299f68))
Attach num: (1) text: (One) class: (Number) self: (Number=HASH(0x1229a538))
Key: (twotwo)	Num: (2)	Txt: (Two)	Object: (Number=HASH(0x12299f68))
Key: (one)	Num: (1)	Txt: (One)	Object: (Number=HASH(0x1229a538))
Key: (two)	Num: ()	Txt: ()	Object: (Number=HASH 0x120b2f78))

The prints in the attach call now show all the values. You can see that the twotwo and one elements are getting the attached structure, but the 'two' is not ... hmmmm

Replies are listed 'Best First'.
Re^2: Basic STORABLE_attach scenario doesn't work
by jaylaw64 (Novice) on Feb 22, 2012 at 23:40 UTC

    OK. I learned something today. Which makes it a good day, even if I did waste about 24 hours of my life on this problem.

    The issue is the use of STORABLE_attach instead of STORABLE_thaw.

    The Number object is not truly a Singleton. There are multiple numbers, this class just ensures that if you ask for an object with the same values you get the same object. But there are multiple objects. (In my real application these are LDAP found users, hurray for Net::LDAP).

    So Storable is smart enough to understand the shared references and "do the right thing". The only issues is how to recreate the $numbers hash during thawing in case objects created after Storable returns are added to the set of known numbers.

    If I define STORABLE_thaw instead of STORABLE_attach, it is only called once for each element of the $numbers hash, I just have to put them back during the thaw. Here is the new numbers class. I've added a new method _populate that is used by both the constructor and the thaw routine to fill in the object and the numbers hash

    package Number; use strict; # Hash to hold singletons use vars qw ($numbers); $numbers = {}; sub new { my ($class, $number, $text) = @_; # Check for and return an existing singleton return $numbers->{$number} if ($numbers->{$number}); # Build the object my $self = {}; bless($self, $class); # Fill in the values $self->_populate($number, $text); return $self; } sub _populate { my ($self, $number, $text) = @_; $self->{'number'} = $number; $self->{'text'} = $text; # Store it as the singleton definition and return $numbers->{$number} = $self; return $numbers->{$number}; } sub asNumber { my ($self) = @_; return $self->{'number'}; } sub asText { my ($self) = @_; return $self->{'text'}; } sub STORABLE_freeze { my ($self, $cloning) = @_; my $num = $self->asNumber(); my $txt = $self->asText(); my $numTxt = "$num$txt"; print "Freeze $numTxt\n"; return "$num$txt"; } sub STORABLE_thaw { my ($obj, $cloning, $serialized) = @_; my ($num, $txt) = ($serialized =~ /(\d+)(\w+)/); printf("Thaw num: ($num) text: ($txt) obj: ($obj)\n", $num, $txt, +$obj); $obj->_populate($num, $txt); return; } 1;

    For completeness here is the creator script

    #!/usr/bin/env dvperl use strict; use Number; use Storable; my $stuff = {'one' => new Number(1, "One"), 'two' => new Number(2, "Two"), 'twotwo' => new Number(2, "Two")}; foreach my $key (keys %$stuff) { my $number = $stuff->{$key}; my $num = $number->asNumber(); my $txt = $number->asText(); print ("Key: ($key)\tNum: ($num)\tTxt: ($txt)\tObject: ($number)\n +"); } store $stuff, 'storefile';

    And the reader script

    #!/usr/bin/env dvperl use strict; use Number; use Storable; my $stuff; $stuff = retrieve 'storefile'; foreach my $key (keys %$stuff) { my $number = $stuff->{$key}; my $num = $number->asNumber(); my $txt = $number->asText(); print ("Key: ($key)\tNum: ($num)\tTxt: ($txt)\tObject: ($number)\n +"); }

    The output of creating

    Key: (twotwo)	Num: (2)	Txt: (Two)	Object: (Number=HASH(0x3bca6a0))
    Key: (one)	Num: (1)	Txt: (One)	Object: (Number=HASH(0x3badf78))
    Key: (two)	Num: (2)	Txt: (Two)	Object: (Number=HASH(0x3bca6a0))
    Freeze 2Two
    Freeze 1One
    

    Note: 'two' and 'twotwo' are the same reference but only one STORABLE_freeze call for 2 was made

    And finally, the output of the reader script

    Thaw num: (2) text: (Two) obj: (Number=HASH(0x1ed62f78))
    Thaw num: (1) text: (One) obj: (Number=HASH(0x1edaab80))
    Key: (twotwo)	Num: (2)	Txt: (Two)	Object: (Number=HASH(0x1ed62f78))
    Key: (one)	Num: (1)	Txt: (One)	Object: (Number=HASH(0x1edaab80))
    Key: (two)	Num: (2)	Txt: (Two)	Object: (Number=HASH(0x1ed62f78))
    

    The lesson is only use STORABLE_attach for literal singleton objects. Now I can complete my transition from using Data::Dump to Storable, and get back to my real job.

    This is my first post to perlmonks and although I eventually figured this one out myself, I am grateful for the many times I have solved a problem by simply tapping into the wisdom of the monks. I leave this detailed explanation in the hopes that it will be found in the future by someone as lost as myself. Despite the power of google I could not find another complete example.