in reply to Re: Basic STORABLE_attach scenario doesn't work
in thread Basic STORABLE_attach scenario doesn't work

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.