in reply to Re: coderefs and storable
in thread coderefs and storable

Alternatively ...
my $coderef = do { my $x = 10; sub { print "\nx is : $x\n"; }; };

------
We are the carpenters and bricklayers of the Information Age.

Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Replies are listed 'Best First'.
Re: Re: Re: coderefs and storable
by amw1 (Friar) on Mar 12, 2004 at 19:37 UTC
    ultimately what I'm trying to do is to insert an action (as a serialized code ref) into a database to be run at a later time. $x will need to change for different instances of the coderef. Something like. . . . (pseudo code)
    sub RemoveThing { my $thingid = shift(); # QueueAction serializes it's first argument QueueAction(\&Handlers::thing_remove()) } package Handlers; sub thing_remove { database foo to remove $thingid; }
    I know I can make QueueAction take an argument list for passing to the serialized subroutine. Just trying to avoid it.
      Well, with that structure you're going to have some trouble no matter what you do since thing_remove can't see $thingid even if you evaluated it directly in the RemoveThing subroutine.

      But let's say that you change thing_remove to accept an argument, or have some other way of passing the information on down. Then, something I've done in similar situations is this: (warning: it ain't pretty)

      sub RemoveThing { my $thingid = shift(); my $thingtodo = q[sub {&Handlers::thing_remove("_thingid");}]; $thingtodo =~ s/\b_thingid\b/quotemeta($thingid)/ge; $thingtodo = eval($thingtodo); # QueueAction serializes it's first argument QueueAction($thingtodo); }
      The problem that you have here is that you want to partially evaluate some of the references inside your subroutine, but not others. That is, I'm sure that thing_remove depends on some global state (handle to the database and whatnot) which you don't want passed through the serialization but also on some variables whose values you would like serialized. The only I know of to do that is to get perl to eval some string that happens to contain the appropriate values.

      By the way, this isn't, really, quite the same thing as serializing a closure - a closure captures the binding of variables, but what you want serialized is the value of those variables. As an example of the difference, consider this:

      my @tasks = (); { my $x = 'A'; push @tasks, sub {print "Doing task $x\n";}; } { my $x = 'B'; push @tasks, sub {print "Doing task $x\n";}; } foreach (@tasks) {$_->();}
      versus this:
      my @tasks = (); my $x; $x = 'A'; push @tasks, sub {print "Doing task $x\n";}; $x = 'B'; push @tasks, sub {print "Doing task $x\n";}; foreach (@tasks) {$_->();}
      The second batch of code prints B twice! This is because a closure doesn't really capture the value of the variable at the time it's created - it captures the binding.

      For the record, I'm not entirely sure what it would mean to serialize a closure with the bindings intact.

        Thanks for taking the time to break this all the way down. I' ll give it a try over the weekend.