Swandog has asked for the wisdom of the Perl Monks concerning the following question:

I have a feeling I know the answer to this, but I thought I would see if there's something I don't know.

For reasons beyond the scope of this question, I have a program that is eval-ing the content of a lot strings (well, files, but whatever). The problem is that a lot of those files have subroutines defined in them as helpers, and they often have the same name. So when I eval them one after another, I get a lot of "subroutine redefined" warnings.

Here's some code that essentially demonstrates the problem:

#/usr/bin/perl use warnings; use strict; sub eval_string { my $string=shift; eval $string; } my $string1=" sub foo { print qq(first definition\n); } foo(); "; eval_string($string1); my $string2=" sub foo { print qq(second definition\n); } foo(); "; eval_string($string2);

and the output:

~>perl test.pl first definition Subroutine foo redefined at (eval 2) line 2. second definition

I know I can get around this by declaring "no warnings 'redefine'" right before my eval, but I feel like that's a second-best solution. If someone did something really stupid and redefined a subroutine used outside the eval, I'd want to know that.

Obviously it would be easier if the strings created anonymous subroutines instead of defining named subroutines, but again, beyond the scope. What I'm wondering is if there's a way to tell eval to not, essentially, "import" any subroutines defined in the execution of the eval. Or, if there is an existing alternative to eval (on CPAN or some such) that does this for me.

If not, I can deal with this. I just thought I'd probe the mind of the community.

Thanks for any help!

Replies are listed 'Best First'.
Re: Prevent import of subroutines from eval
by choroba (Cardinal) on Oct 10, 2013 at 22:24 UTC
    You can forget the definition of the sub, just put the following before the second eval:
    delete $::{foo};

    Alternatively, use different packages in the evals. Just prepend

    package eval1; # eval2 respectively

    to each string.

    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
      ... use different packages in the evals. Just prepend ...

      ++Ooo, that works very nicely!

      c:\@Work\Perl>perl -wMstrict -le "sub foo { print __PACKAGE__, ' foo'; } ;; my $e_str = q{sub foo { print __PACKAGE__, ' foo'; }; foo(); }; ;; for my $n (1 .. 3) { my $p = qq{package Bar$n; }; eval $p . $e_str; } ;; foo(); Bar1::foo(); Bar2::foo(); Bar3::foo(); " Bar1 foo Bar2 foo Bar3 foo main foo Bar1 foo Bar2 foo Bar3 foo

      Something about modifying other people's code programmatically rubs me the wrong way. But given what the original code is doing, maybe I just need to get over it.

      Thanks for the suggestion.

        This does not modify any code. It just adjusts the symbol table.
        لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Prevent import of subroutines from eval (fork or exec)
by tye (Sage) on Oct 11, 2013 at 02:35 UTC
    I have a program that is eval-ing the content of a lot strings

    (Emphasis added.) Defining a new package name for each one is going to just keep adding memory consumption.

    You might want to fork() and have the child evaluate the code. Or you might want to, every so often, re-exec the script to reset the memory consumption. Which is easier depends on which is more complicated: the data you get out of running the eval'd code or the program's "state" so that the new instance can properly continue where the prior instance left off.

    use strict; my $pid = open my $pipe, "-|"; die "Can't fork: $!\n" if ! defined $pid; if( ! $pid ) { my $output = eval ...; print $output; exit; } local $/; my $output = <$pipe>; close $pipe;

    Or

    if( been_a_while() ) { system( $^X, $0, "--restart=$context", @ARGV ); }

    - tye        

      > Defining a new package name for each one is going to just keep adding memory consumption.

      so what about just deleting the namespace?

      DB<123> ; {package TMP; eval 'sub bla {"BLA"}'} DB<124> TMP::bla() => "BLA" DB<125> delete ${'main::'}{'TMP::'} => do { my $a = *main::TMP::; $a = { bla => *TMP::bla }; $a; } DB<126> TMP::bla() Undefined subroutine &TMP::bla called at (eval 72)[multi_perl5db.pl:64 +4] line 2.

      Cheers Rolf

      ( addicted to the Perl Programming Language)

      Well, fortunately, the program is not particularly long running (< 3 minutes), so memory consumption is not a huge concern to me.

      I might have overreached with my use of the phrase "a lot". I'm talking about 30 or so.

Re: Prevent import of subroutines from eval
by LanX (Saint) on Oct 10, 2013 at 22:22 UTC
    You could use throw-away package names as target for the imports.

    Since you get these redefined messages I suppose they are normally imported into main.

    If your "files-beyond-scope" already have package declarations on their own, this won't work.

    Cheers Rolf

    ( addicted to the Perl Programming Language)

Re: Prevent import of subroutines from eval
by Anonymous Monk on Oct 10, 2013 at 22:18 UTC