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. |