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

Consider the following line of code:

$value += $var1 || $var2;

This doesn't work if $var1 is 0.00, because perl doesn't evaluate it as a number, but as a string. To get it to work, I have to do:

$value += eval $var1 || eval $var2;

This works now, but it's inside a very long loop. Should I regard eval as expensive and use it sparingly, only when I really need it? Are there rules of thumb as to when eval is efficient and when it's wasteful?

Replies are listed 'Best First'.
Re: When is 'eval' too inefficient?
by Corion (Patriarch) on Oct 12, 2007 at 12:59 UTC

    Using eval is almost always overkill, especially when your data already has a well-defined structure. In your case, you seem to be using floating point numbers, so you might want:

    my $increment = ($var1 + 0) || $var2; $value += $increment;

    If your numbers are actually strings being read in from a file, an explicit string comparison might be even more explicit:

    my $increment = ($var1 ne '0.00') ? $var1 : $var2;

    The rule of thumb is to always avoid the string form of eval, because there are almost always more efficient ways around it unless you need to parse arbitrary Perl code.

      You're right about the floating numbers--it's never the case that one of the variables would be undefined. The use of "+0" is precisely the solution, but dare I say, an inelegant one. If I can say int $var1, I think there should be an equivalent counterpart for real numbers, as in real $var1 or float $var1.

      Though the problem is solved, I'm still curious about the broader question of eval that I originally asked: is there a rule of thumb as to how inefficient it may be? Are there suggestions about when it's best to avoid it, and best to use it?

        To argue that Perl should provide a function to convert a scalar to a float because it provides a function to convert a scalar to an integer is a valid argument, but the premise is false. Perl doesn't have a function that converts a scalar to an integer.

        int implements the mathematical function. It doesn't necessarily return an integer in the C sense of the word. For example, here's an example where int returns a float (NV):

        >perl -MDevel::Peek -e"Dump int(2**32);" SV = NV(0x184ac1c) at 0x226be4 REFCNT = 1 FLAGS = (NOK,pNOK) NV = 4294967296

        Type conversion is always done implicitely in Perl.
        If Perl needs a string, the scalar will be coerced into a string.
        If Perl needs a number, the scalar will be coerced into a number.
        If Perl needs a boolean, the scalar will be coerced into a boolean.
        etc.

        Of course, you are free to produce your own conversion routines.

        sub to_string { "$_[0]" } sub to_num { 0+$_[0] } sub to_bool { !!$_[0] } etc.

        Person 1: This is my favorite horse.
        Person 2: Isn't that your only horse?

        In the general sense, eval is the most efficient function. There's simply no alternative.

        In specific situations where there is an alternative, the alternative is probably more efficient (and safer and more maintainable). You'll have to benchmark the two for more details.

Re: When is 'eval' too inefficient?
by ikegami (Patriarch) on Oct 12, 2007 at 13:16 UTC

    Be careful when you omit parens. You got lucky because of eval's prototype, but other functions aren't as forgiving.

    eval $var1 || eval $var2;
    means
    eval($var1) || eval($var2);

    For non-exceptional functions,
    func $var1 || func $var2;
    means
    func($var1 || func($var2));

Re: When is 'eval' too inefficient?
by ikegami (Patriarch) on Oct 12, 2007 at 13:07 UTC
    The problem with eval EXPR is not efficiency, it's danger. It's harder to maintain and debug, and it's more successible to injection attacks and bugs.
Re: When is 'eval' too inefficient?
by Fletch (Bishop) on Oct 12, 2007 at 13:00 UTC

    If you want a number force numeric conversion.

    $ perl -le '$var1 = "0.00"; $value += ($var1+0) || 99; print $value' 99

    And your use of eval there is string eval so yes that's expensive and not really a good idea.

Re: When is 'eval' too inefficient?
by dsheroh (Monsignor) on Oct 12, 2007 at 14:21 UTC
    As I read your question, it looks like you're trying to add $var1 if it's defined or $var2 if it isn't, but you're getting tripped up by testing whether $var1 is true instead.

    If my interpretation is correct, then test for definedness with defined:

    $value += defined $var1 ? $var1 : $var2;
Re: When is 'eval' too inefficient?
by eyepopslikeamosquito (Archbishop) on Oct 12, 2007 at 22:51 UTC
Re: When is 'eval' too inefficient?
by codeacrobat (Chaplain) on Oct 12, 2007 at 19:55 UTC
    I eagerly await the "defined" and "defined-or" operator of Perl 5.10
    $val = expr1 // expr2; $val //= expr3;
    This will fix many conditional assignment bugs involving checks on zero.

    print+qq(\L@{[ref\&@]}@{['@'x7^'!#2/"!4']});
      The problem value '0.00' is defined. // would still give the undesired result.
Re: When is 'eval' too inefficient?
by DrHyde (Prior) on Oct 15, 2007 at 11:37 UTC

    Have you benchmarked it? That will tell you whether using eval is faster or slower than just adding 0 to force things to be numeric.

    Have you profiled it? That will tell you whether you should care.