I'd like to be able to write something like the following...
call_with_scope({
x => 47,
}, sub {
printf "$x\n";
printf "$y\n";
});
Where $y is bound in the environment containing the expression (either lexically or dynamically depending on the symbol).
I've found a way to do it, but it requires no strict "vars" to be in effect in the expression containing call_with_scope(...) and the implementation of call_with_scope uses eval to create local bindings before transferring control to the callback.
Is there a way to avoid either requiring no strict "vars" at the call site or refer to and change the value of a local variable without resorting to eval?
For completeness, the code snippet below implements call_with_scope and prints 47 and then 48.
#!/usr/bin/env perl
use strict;
use warnings;
sub call_with_scope {
my ($env, $func) = @_;
my %property;
my @preamble;
foreach my $k (keys %$env) {
$property{$k} = $env->{$k};
# deliberately omitted: logic to ensure that ${$k} is a well-formed variable
push @preamble, "local \$$k = \$property{'$k'};";
}
# force scalar context
do {
my $str = join('', 'no strict "vars";', @preamble, '$_[1]->();');
return scalar(eval($str));
};
}
do {
no strict 'vars';
local $x;
my $y = 48;
call_with_scope(
{
x => 47,
},
sub {
printf "$x\n";
printf "$y\n";
}
);
};