Can I make different snippets of eval
ed Perl code share the same lexical scope and yet get their return values?
Background
Perl's eval command evaluates a string as Perl code and upon success returns the value of the last statement in that code. However, lexical variables created in that code are dropped at the end of the code. This means when eval of code1 has ended and I have a second code chunk code2, which refers to the lexical variables set in code1, this will fail.
my $code1 = 'my $c = 4';
my $code2 = 'printf "%g\n", $c;';
printf 'evaluated "%s" to %s' . "\n", $code1, eval $code1;
printf 'evaluated "%s"' . "\n", $code2;
yields
evaluated "my $c = 4" to 4
evaluated "printf "%g\n", $c;"
but not a line containing just 4
as I would wish, because $code2
should use the variable $c
if lexical scopes are re-used. (I generally agree with the default that lexical scopes are constrained to only one eval
ed code, so I expect that some conscious modification of code is required to make the above work.)
Approaches considered
I experimented with use PadWalker qw( peek_my );
to save the lexical scope at the end of each code snippet aiming to load it into the scope of the following snippet, but then I realised that this would make inaccessible the return value of the code snippet, which is needed by the calling code.
As another alternative appears to pattern-match (probably using a dedicated parser) all my
-declarations in the perl code snippets and essentially translate them on the fly, but this would amount to a considerably bigger task.
Template example for discussion (see comments)
\perlExec{
use PDL;
my $v = vpdl [ 1, 2 ];
my $w = vpdl [ 3, 4 ];
sub list ($) {
my $pdl = shift;
return join ',', map { at( $pdl, $_, 0 ) } 0..1;
}
}
The vector [ \perlValue{ list $v } ]
plus the vector [ \perlValue{ list $w } ]
makes [ \perlValue{ my $s = $v + $w; list $s } ].
Perhaps you would like to use Eval::WithLexicals? It does exactly what you are asking for. It was designed to power REPLs, and it's pure Perl. You simply make a new instance of Eval::WithLexicals
, and then you call $ewl->eval($code)
instead of eval $code
, and the variables will persist between successive calls on the same object.