Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the Storable CPAN distribution.

Report information
The Basics
Id: 11813
Status: new
Priority: 0/
Queue: Storable

People
Owner: Nobody in particular
Requestors: cpan [...] ali.as
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 2.13
Fixed in: (no value)



Subject: Storable incompatible with singleton classes
Storable spuriously creates illegal blessed hash references in STORABLE_thaw. This bug is related to bug #4901 and bug #6641, and will be fixed if point 2) from bug #6641 is implemented, but I'm adding it here as a seperate case, primarily because I've encapsulared the issue as a test case you can add to the Storable dist. ------------------------------------------------ singleton.t ------------------------------------------------ #!/usr/bin/perl -w # Tests the freezing/thawing structures containing Singleton objects, # which should see both structs pointing to the same object. # In order to make this test work, ANY method needs to exist that can # be used in STORABLE_freeze and STORABLE_thaw in order to make the tests # pass. use Storable (); use Test::More tests => 7; # Get the singleton my $object = My::Singleton->new; isa_ok( $object, 'My::Singleton' ); # Confirm (for the record) that the class is actually a Singleton my $object2 = My::Singleton->new; isa_ok( $object2, 'My::Singleton' ); is( "$object", "$object2", 'Class is a singleton' ); ############ # Main Tests my $struct = [ 1, $object, 3 ]; # Freeze the struct my $frozen = Storable::freeze( $struct ); ok( (defined($frozen) and ! ref($frozen) and length($frozen)), 'freeze returns a string' ); # Thaw the struct my $thawed = Storable::thaw( $frozen ); # Now it should look exactly like the original is_deeply( $struct, $thawed, 'Struct superficially looks like the original' ); # ... EXCEPT that the Singleton should be the same instance of the object is( "$struct->[1]", "$thawed->[1]", 'Singleton thaws correctly' ); # We can also test this empirically $struct->[1]->{value} = 'Goodbye cruel world!'; is_deeply( $struct, $thawed, 'Empiric testing corfirms correct behaviour' ); # End Tests ########### package My::Singleton; my $SINGLETON = undef; sub new { $SINGLETON or $SINGLETON = bless { value => 'Hello World!' }, $_[0]; } sub STORABLE_freeze { my $self = shift; # We don't actually need to return anything, but provide a null string # to avoid the null-list-return behaviour. return (''); } sub STORABLE_thaw { my ($obj, $string) = @_; # Get the Singleton object my $self = My::Singleton->new; ### IS THERE ANY POSSIBLE CODE FOR STORABLE_thaw THAT CAN ### BE USED TO PASS THE TESTS??? ### LET'S TRY TO DOCUMENTED WAY OF CREATING THE OBJECT %$obj = %$self; return; } # This one would work under the proposed changes to Storable sub STORABLE_thaw_new { My::Singleton->new; }
Indeed, you've hit a limitation of the Storable engine. Fixing this to get the correct behavior requires great care because the reason Storable creates objects for you to fill is that it handles all the cross-referencing between ojects to make sure the proper topology is recreated. If you want to insist that a particular object instantiated by Storable be replaced by a singleton instance, then you need to inform the core about that. It's not practical to let STORABLE_thaw return an object of youts, because when the singleton reference was serialized, it pointed to some objects (maybe) that will be deserialized as well later on (or were already re-instantiated), unless you made your own custom STORABLE_freeze hook to supersede the default serialization. Patching the structure after is has been completely instantiated could be an option, but it may require a retraversal of the whole thing to break the references to the "singleton" and force them to point back to your instance. A way to inform the Storable core about that would be to call the core from within STORABLE_thaw and inform it about the fact that the object requires special treatment. A "cleanup" phase on the the structure recreated could then be performed whenever this core routine was called during deserialization, so as to not impose a penalty on the regular cases -- I mean, the problem you've hit is genuine but is not something all that common. My humble comments as the original author. I've not been following the recent developments of Perl, so maybe all what precedes is just stupid and irrelevant.
From: cpan [...] ali.as
Show quoted text
> Indeed, you've hit a limitation of the Storable engine. > > Fixing this to get the correct behavior requires great care
Correct. You might want to take a look at bug #4901, where most of the ongoing conversation relating to the changes that will be needed is being discussed. Fortunately, I'm not a strange to complex topology algorithms, since I've written some before to deal with manipulation of arbitrarily complex relational database data sets. After various comments from people here and in #perl, I think we have an idea for what will be needed, and I'll be whiteboarded up some sample topologies to have a play shortly.