in reply to eval something using private copy of variables

If the code you're evaluating is non-perverse, you can use a temporary package:
my $pkg = 'AAAAAAAAAA'; sub EVAL { ++$pkg; if (wantarray) { my @res = eval <<EOS; package $pkg; @_ EOS eval 'undef %'.$pkg.'::'; @res; } else { my $res = eval <<EOS; package $pkg; @_ EOS eval 'undef %'.$pkg.'::'; $res; } }

Replies are listed 'Best First'.
Re^2: eval something using private copy of variables
by gboole (Novice) on Aug 19, 2007 at 19:42 UTC
    Thanks for the quick response, which seems very promising especially as I hadn't delved into namespaces before now. Unfortunately, while it solves one half of the problem (protecting outer copies of the variables), it does not solve the other (copying the outer variables to the inner namespace).

    For instance if I initialize $i to 3 via "$i=3;" or "local $i=3;" early in main, and then feed line input to EVAL via:

    for (;$line=<>;) { $v = EVAL($line); print "answer is $v\n"; }
    then $i is initially undefined in the local package, so the input "++$i" gives "answer is 1" every time, rather than the desired "answer is 4" every time.

    I would like to import from main all variables that are used in this particular call to EVAL(). More precisely, when EVAL($line) encounters a variable ($i, say) while evaluating $line:

    (b) if $i is already defined in the local namespace, use that value (could happen if $i were assigned earlier in the evaluation of the same $line).

    (a) otherwise, import $i from main;

    If the only solution is to explicitly import named variables we would need to parse $line to discover what variables it uses. This seems like an ugly non-ideal solution but it is feasible as a last resort because I only want a solution that works right for most scalar purely numeric expressions, rather than one that works when $line includes strings, function calls, etc. But is there a more beautiful solution?

      Seems like an overkill, but if you really want ALL your variables available for the user, that essentially is equivalent to making a copy of the entire symbol table, and handing it over the the user to mess with. The only way to reconstruct it is to save everything. That is essentially a fork or a thread, so this works
      use threads; my $x=1; my $threads = threads->new(sub {eval '(++$x)+1'}); print "The value of \$x before eval is $x\n"; my $val = $threads->join(); print "The eval returned $val\n"; print "The value of \$x after eval is $x\n";
      giving the result
      The value of $x before eval is 1 The eval returned 3 The value of $x after eval is 1
      It seems like overkill, but then, you asked for it. Less expensive might be to copy that part of the symbol table that you want shared with the user, and restore it after they are done.
        This particular swine thanks you for your Perl wisdom! I didn't know of the concept of Perl threads but they seem perfect for my application.

        Of course copying the whole symbol table seems like overkill, but this is for a resource-light calculator program, so the extra time and memory involved seems fine e.g. it took 8K-15K microsec for repeat runs of one simple threaded test vs 70-150 microsec for unthreaded. Waiting .015 sec or so for an answer from a calculator seems acceptable. Since Perl cleans up threads after use, all should be well even if the calculator is left running for a long time.