views:

97

answers:

1

I think this might be best asked using an example:

use strict;
use warnings;
use 5.010;
use Storable qw(nstore retrieve);

local $Storable::Deparse = 1;
local $Storable::Eval    = 1;

sub sub_generator {
    my ($x) = @_;

    return sub {
        my ($y) = @_;
        return $x + $y;
    };
}

my $sub = sub_generator(1000);
say $sub->(1); # gives 1001
nstore( $sub, "/tmp/sub.store" );
$sub = retrieve("/tmp/sub.store");
say $sub->(1); # gives 1

When I dump /tmp/sub.store I see:

$VAR1 = sub {
            package Storable;
            use warnings;
            use strict 'refs';
            my($y) = @_;
            return $x + $y;
        }

But $x is never defined in this sub. I would expect that the sub generated by sub_generator will have $x replaced with its actual value upon generation. How should I solve this?

Note this question relates to this one.

+5  A: 

Unfortunately I don't think Storable works with closures. However there are other CPAN modules that will serialise a closure. For eg. Data::Dump::Streamer

use 5.012;
use warnings;
use Data::Dump::Streamer;

sub sub_generator {
    my ($x) = @_;

    return sub {
        my ($y) = @_;
        return $x + $y;
    };
}

my $sub = sub_generator(1000);
say $sub->(1); # gives 1001

my $serialised = Dump( $sub )->Out;
my $copy = do {
    my $CODE1 = undef;
    eval $serialised;
    $CODE1;
};

say $copy->(2); # gives 1002
say $sub->(1);  # still gives 1001

This is what the serialised code looks like when printed here, say Dump $sub;:

my ($x);
$x = 1000;
$CODE1 = sub {
           use warnings;
           use strict 'refs';
           BEGIN {
             $^H{'feature_unicode'} = q(1);
             $^H{'feature_say'} = q(1);
             $^H{'feature_state'} = q(1);
             $^H{'feature_switch'} = q(1);
           }
           my($y) = @_;
           return $x + $y;
         };


Update

See this thread Storable and Closures on the Perl5 porters mailing list. It confirms what I thought about Storable and closures.

/I3az/

draegtun
What am I doing wrong? I get an empty file: `use Data::Dump::Streamer; my $h={A=>1, B=>2}; open (my $fh, ">", "/tmp/DEL"); Dump($h)->To($fh) or die; close ($fh);`
David B
`Dump($h)->To($fh)->Out` will do the trick.
draegtun
Thank you draegtun.
David B