in reply to Re: eval problem
in thread eval problem

Thanks. I don't understand this error:

Modification of a read-only value

I don't see how I'm trying to modify $1.

You should have checked if the eval succeeded.

I read the docs on eval(), and I have no idea what it does. I know what eval does in other languages, but I couldn't get a single example using eval to work in perl. The examples in the docs are really poor.

Replies are listed 'Best First'.
Re^3: eval problem
by ikegami (Patriarch) on Dec 03, 2009 at 21:31 UTC

    Your evaluating --$1, where -- is the predecrement operator.

    I read the docs on eval(), and I have no idea what it does

    Seems pretty straight forward to me

    [For eval EXPR], the return value of EXPR is parsed and executed as if it were a little Perl program. The value of the expression (which is itself determined within scalar context) is first parsed, and if there weren't any errors, executed in the lexical context of the current Perl program.

    As for errors,

    If there is a syntax error or runtime error, or a die statement is executed, eval returns an undefined value in scalar context or an empty list in list context, and $@ is set to the error message. If there was no error, $@ is guaranteed to be a null string.

    I couldn't get a single example using eval to work in perl.

    $ perl -le'print "Hello, World!";' Hello, World! $ perl -le'eval q{print "Hello, World!";};' Hello, World!
    The difference is that you can build the code dynamically
    $ perl -le'print "3$ARGV[0]4";' + 3+4 $ perl -le'print eval "3$ARGV[0]4"' + 7 $ perl -le'print eval "3$ARGV[0]4"' '*' 12

    Be careful about using external inputs:

    $ perl -le'print $ARGV[0]' '`rm -i *`' `rm -i *` $ perl -le'print eval $ARGV[0]' '`rm -i *`' rm: remove regular file `demo.pl'? ^C

      Your evaluating --$1, where -- is the predecrement operator.

      Ah. That was a bad choice of characters in my example.

      Also, there is nothing in the eval docs to indicate why this doesn't work:

      my $temp = 'xxx$1'; my $repl = eval q{"$temp"};

      In other words, why are double double quotes required? Shouldn't the q{} operator return whatever is inside it without interpolation? Wouldn't that be "$temp"? And when "$temp" is eval()'ed wouldn't the qq{} operator around $temp return a string with the $variables interpolated? Or, is it that eval() only does one pass of interpolation over "$temp" leaving me with:

       my $repl = "xxx$1";

      and therefore a first pass of interpolation is necessary with qq{} to present eval with "xxx$1"?

      Seems pretty straight forward to me

      For eval EXPR, the return value of EXPR is parsed and executed as if it were a little Perl program. The value of the expression (which is itself determined within scalar context) is first parsed, and if there weren't any errors, executed in the lexical context of the current Perl program.

      Let's test out this eval EXPR thing. First, I need an expression that returns a perl statement that can then be "executed as if it were a little program". The following code seems to produce an expression that I can use:

      use strict; use warnings; use 5.010; my $x = 10; my $result = sprintf '%s', 'my $y = $x;'; say $result; --output:-- my $y = $x;

      The return value of the sprintf expression is the string that is displayed. Ok, now I'm going to eval that expression. According to the docs you quoted, the value of the expression will be "executed in the lexical content of the current Perl program"--whatever that means. I'll try using eval() and see what happens:

      my $x = 10; eval (sprintf '%s', 'my $y = $x'); say $y; #line 14 --output:-- Global symbol "$y" requires explicit package name at 2perl.pl line 14. Execution of 2perl.pl aborted due to compilation errors.

      I thought I followed the instructions in the docs to the letter, but eval EXPR just spits out errors. What about the block form of eval(): eval BLOCK? The docs say:

      the BLOCK is parsed only once‐‐at the same time the code surrounding the "eval" itself was parsed‐‐and executed within the context of the current Perl program.

      This seems much easier; no sprintf necessary:

      my $x = 10; eval {my $y = $x}; say $y; #line 14 --output:-- Global symbol "$y" requires explicit package name at 2perl.pl line 14. Execution of 2perl.pl aborted due to compilation errors.

      The heck with the descriptions, I'll examine a couple of examples in the docs and figure it out by myself. Hmmm...none of the examples in the docs will work either because they are incomplete.

      So...no. The docs do not seem straightforward to me.

        Shouldn't the q{} operator return whatever is inside it without interpolation?

        Yes. The only special sequences in single quotes are: backslash-backslash, backslash-delimiter and delimiter.

        Wouldn't that be "$temp"?

        Yes

        $ perl -le'print q{"$temp"}' "$temp"

        And when "$temp" is eval()'ed wouldn't the qq{} operator around $temp return a string with the $variables interpolated?

        Yes. The value of $temp is interpolated.

        $ perl -le'$temp=q{Bread was $1.50}; print eval q{"$temp"}' Bread was $1.50 $ perl -le'$temp=q{Bread was $1.50}; print "$temp"' Bread was $1.50

        This seems much easier; no sprintf necessary:

        I don't know why you used sprintf in any of the examples. You do realize that

        '...'
        is just as much an expression as
        sprintf('%s', '...')

        right? An expression is a piece of code that can be used as an operand. That includes simple values such as a string.

        I thought I followed the instructions in the docs to the letter, but eval EXPR just spits out errors.

        Not true. eval EXPR doesn't spit out errors. It places them in $@ and you didn't even check $@. The message you posted came from say $y;.

        What you're missing is that Perl programs are compiled and executed in their own scope, usually called "file scope". Think of the eval code as being inside a do{}. Yeah, that could be made more explicit.

        $ perl -E'use strict; my $x = 10; eval q{ my $y = $x; }; say $y' Global symbol "$y" requires explicit package name at -e line 1. Execution of -e aborted due to compilation errors. $ perl -E'use strict; my $x = 10; eval q{ my $y = $x; say $y };' 10 $ perl -E'use strict; my $x = 10; my $y; eval q{ $y = $x; }; say $y' 10 $ perl -E'use strict; my $x = 10; my $y = eval q{ $x }; say $y' 10

        eval {my $y = $x};

        Don't try to apply the docs for eval EXPR to eval BLOCK at all. It's a completely different operator. In Java, C++ and Perl6, it's known as try. It won't help you at all here.

        I missed this question of yours originally

        Or, is it that eval() only does one pass of interpolation over "$temp"

        eval EXPR doesn't interpolate. It parses and executes the Perl code it is provided.

        As for Perl, it doesn't interpolate recursively. Nothing I know does. (Perl, bash, Template-Toolkit, ...) quotemeta would become the most used function if it did.