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

I've been fiddling with trying to resolve scalar values within a string. I've been digging around for a bit and found the eval. If I understand eval right, it's not really meant for what I want or I'm misusing it in some fashion :(

For example, the following code has expected behavior where each scalar value in a string is replaced with the appropriate value.

my $alpha = "A"; my $delta = "D"; my $test = "$delta and $alpha"; print "$test";
Will naturally print the following string;
D and A

Now the following code will behave exactly as I expect it to.

my $alpha = "A"; my $delta = "D"; my $test = '$delta and $alpha'; print "$test";
Of course, it will print
$delta and $alpha
No surprise there.

But what if I want it to evaluate the contents in that scalar as string expression? So I read into eval and I understand it to be meant to use to evaulate actual blocks of code. As in if an Eval block is just a regular block of code. So it returns all the same things a regular block would do. But according to my llama book, it states that it also has the advantage that it protects the primary source from errors. Especially if you're calling third party code and you don't have any assurance that it won't fail gracefully.

So now, I've run out of choice search phrases to try. Any suggestions?

Replies are listed 'Best First'.
Re: Resolving scalars in a scalar
by Zaxo (Archbishop) on Oct 30, 2003 at 03:40 UTC

    There is a slick touch of confusion happening that's worthy of an obfu.

    $ perl -e'($alpha, $delta) = qw{A D};$test = q($delta and $alpha); pri +nt eval $test' A$
    $delta and $alpha are substituted all right, but the and operator gets evaluated, too. 'D' is true, so 'A' is evaluated and becomes the value of the expression.

    I don't know of a way to get double interpolation that will survive this problem.

    Update: Well, there is a way of course, but it's really crude, $test =~ s/\$(\w+}\b/$$1/g;

    After Compline,
    Zaxo

      I realize your regex wasn't meant to be used in a real example, but do realize that Perl will allow far more than \w chars in a variable. You can even get whitespace in there with symbolic refs:

      $ perl -MData::Dumper -e '$field = "foo bar"; *$field = 1; print Data: +:Dumper::Dumper(\%main::)' $VAR1 = { # Cut other variables in output 'foo bar' => *{'::1'}, };

      Of course, you could only access such a beast with another symbolic ref.

      ----
      I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
      -- Schemer

      : () { :|:& };:

      Note: All code is untested, unless otherwise stated

      To clarify, I wrote that original message. I guess I had my cookies off. :)

      The "$delta and $alpha" is supposed to be a string. I'm not sure I understand why 'and' would be evaluated as an operator in that case?

      And some one should fix the reference to and, it points to someone who took that name. Or did you intentionally mean for me to go to his profile? Unfortunately, it flew waaay over my head on that one :(

      I'm also still puzzled on just what 'q' does. I see it here and there, but I'm having trouble finding information about it.

      Is it fair to stick a link to my site here?

      Thanks for you patience.

        q{ } is the equivalent of a single quote - ' '.
        qq{ } is the equivalent of a double quote - " ".
        qx{ } is the equivalent of the back quote - ` `.
        ...

        You should read the chapter "Quote and Quote-like Operators" on CPAN here.

        The code
        $text = eval { '$delta and $alpha' };
        is equivalent to -
        $text = ($delta and $alpha);
        where and is a valid Perl operator. Because $delta is true (not empty), $alpha is evaluated, and $text gets assigned with the value of $alpha, which is 'A'. That's what Zaxo was talking about.

Re: Resolving scalars in a scalar
by bart (Canon) on Oct 30, 2003 at 11:19 UTC
    I think what you really want is either to use something like String::Interpolate, or a templating system. For the latter, see a nice intro in this 4 part article, though I'm sure lots of people here have their own favourite templating system, and are willing to let you know about it.
      You're a god. You've managed to answer two questions, one of which I haven't got around to asking.
      So that's what it's called Interpolate.... That's why it's such a pain to find answers sometimes, I don't the name of what I want to do.

      Is it fair to stick a link to my site here?

      Thanks for you patience.

Re: Resolving scalars in a scalar
by etcshadow (Priest) on Oct 30, 2003 at 03:43 UTC
    eval can evaluate either a block of code or a character string containing code. It returns the return value of that code (last computed value in the block/string).
    $x = 1; $y = 2; $code = "$x + $y"; print $code; print eval $code;
    First print yields "1 + 2", second print yields "3".

    Also, yes, eval sets the global variable $@ to be the value of any exception that was thrown inside of the eval.


    ------------
    :Wq
    Not an editor command: Wq
Re: Resolving scalars in a scalar
by Roger (Parson) on Oct 30, 2003 at 04:09 UTC
    I arrive too late and Zaxo has already posted a solution similar to mine. So instead of repeating the same thing, I have considerred Zaxo's solution and came up with an idea, this may be insane but here it goes: tokenize the input string and evaluate all perl variables, sort of a mini compiler/preprocessor. The tokeniser will be very difficult to implement, I have considered B, but got lazy. Anyway, below is my solution that will work under very specific conditions:
    use strict; my $alpha = "A"; my $delta = "D"; my $theta = "T"; my @hash = qw/ Hello world /; my $test = '@hash $delta and $alpha or $theta are good'; # evaluate perl variables except bare words my $result = qq{@{[ map { m/^[\$@%]./ ? eval $_ : $_ } split/\s/,$test ]}}; print "$result\n";
    And the output -
    Hello world D and A or T are good
      So after mindlessly fiddling with the eval statement, I came up with the following;
      my $alpha = "A"; my $delta = "D"; my $test = "$delta and $alpha"; eval "\$test = \"$test\""; print "$test";
      Is that... right?

      Is it fair to stick a link to my site here?

      Thanks for you patience.

        Ummm, because your $test is quoted inside double quote, your $test = "D and A" even before you go into the eval, so the eval had no effect.

        Change the code slightly as follows -
        my $alpha = "A"; my $delta = "D"; my $test = '$delta and $alpha'; eval "\$test = \"$test\""; print "$test";
        and yes, it will work this time, because the code is equivalent to -
        my $alpha = "A"; my $delta = "D"; my $test = '$delta and $alpha'; $test = "$delta and $alpha"; print "$test";
        Where the variable $test inside double quote " " has been expanded by the perl interpreter to the value of $test before going into eval