Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

eval question

by rhymejerky (Beadle)
on Jan 06, 2011 at 19:35 UTC ( #880918=perlquestion: print w/ replies, xml ) Need Help??
rhymejerky has asked for the wisdom of the Perl Monks concerning the following question:

Hi, If I have
$a = 3; $b = 4; $op = 'le';
Is it possible to do $r = eval("$a $op $b") where $r = 1 because 3 is lte 4? Reason I want to do that is because I have I have some operators pass in, in the form of 'le', 'gt', 'eq'. Currently, I do a if statement for each operator like
if ($op eq 'le') { if ($a <= $b) { do something } else { do something else } } elsif ($op eq 'ge') if ($a >= $b) { do something } else { do something else } } elsif ....
Just want to see if there is a cleaver way to consolidate all those if-else statement into 1 TIA

Comment on eval question
Select or Download Code
Re: eval question
by Anonyrnous Monk (Hermit) on Jan 06, 2011 at 19:49 UTC
    Is it possible to do $r = eval("$a $op $b")

    In principle yes, if you map the operators 'le', 'ge' etc. to the corresponding Perl equivalents — e.g. using a hash.

    my %perlop = ( le => '<=', ge => '>=', #... ); my $r = eval "$a $perlop{$op} $b";

    (But as always with string eval, be careful what you interpolate when the data ($a, $b here) doesn't come from trusted sources...)

      (But as always with string eval, be careful what you interpolate when the data doesn't come from trusted sources...)

      If you whitelist allowed operators via hash, and don't interpolate $a and $b, you should be fine:

      if (exists $perlop{$op}) { my $r = eval "\$a $perlop{$op} \$b"; } else { die "OH NOEZ!"; }

      That way the string passed to eval contains the variable names, and obtains their value from the outer scope.

Re: eval question
by jwkrahn (Monsignor) on Jan 06, 2011 at 20:08 UTC
    my %op_table = ( le => sub { $_[0] <= $_[1] }, ge => sub { $_[0] >= $_[1] }, # etc. ); exists $op_table{ $op } or die "The operator '$op' does not exist.\n"; if ( $op_table{ $op }->( $a, $b ) ) { do something } else { do something else }
      I ended up implementing it using your hash. I was thinking about doing eval and string comparison, but this would not work for cases like comparing 5 le 14. Also, not using eval save me from firing another process

        String eval doesn't launch another process. It merely runs the compiler again.

Re: eval question
by eyepopslikeamosquito (Canon) on Jan 06, 2011 at 20:17 UTC

    Be aware that most Perl experts discourage the use of string eval. For example:

    • merlyn in •Re^2: Dynamically constructed function calls states: Do not resort to eval-string if other means are available. You're firing up the compiler (slower than almost any other solution), and exposing yourself to hard to debug and hard to secure practices.
    • In this quiz of the week MJD states: A good rule of thumb is that unless what you're trying to do is most clearly described as "compile and run arbitrary Perl code", it's probably a mistake to use 'eval' to do it.
    • Perl Best Practices, Chapter 8, has a guideline titled: Avoid string eval. Conway argues that string eval can be slow; produces run time warnings rather than more desirable compile time warnings; and code that generates other code tends to be harder to maintain.

Re: eval question
by ikegami (Pope) on Jan 06, 2011 at 20:22 UTC

    Bah, if you have to use a hash anyway, eval doesn't help any.

    my %perlop = ( lte => sub { $_[0] <= $_[1] }, gte => sub { $_[0] >= $_[1] }, # ... ); my $r = $perlop{$op}->($a, $b);

    (Oops, seems I had the page opened a while without realising it, and others have already answered this since then.)

Re: eval question
by sundialsvc4 (Abbot) on Jan 07, 2011 at 01:53 UTC

    I just don’t like “clever solutions” anymore.   The strategy that always seems to work best, at least for yours truly, is to find the simplest and most-obvious way to write code that expresses what you truly mean to say.   Then, let the mighty Perl interpreter do the rest.   After all, microprocessors are never going to slow down anytime soon.   They’ll only become faster.   But software maintenance and development costs will only increase.   And it will be the “clever” solutions, i.e. “the ones that surely must have mightily impressed the programmer himself,” that will bite you in the a*s first.   (Usually at three o’clock in the morning.)

      I guess I was looking for a cleaner solution than a more clever solution. With the hash, I was able to cut out 100 lines of repeated code and I can easily add addition operation using the hash. But I agree with you, I rather read longer code that is self explanatory than a bunch of clever hacks string together

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://880918]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (9)
As of 2014-09-22 13:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (193 votes), past polls