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

hello monks,
i am trying to store operators in a variable and then use the variable as the operator in a condition. e.g

$op = "eq"; if($somvar $op "some text"){ #do this }

have tried many techniques to interpolate the variable and have had no luck. any ideas.

thanks

20040720 Janitored by Corion: Added formatting

Replies are listed 'Best First'.
Re: interpolating a variable into an operator
by Corion (Patriarch) on Jul 20, 2004 at 14:27 UTC

    While eval is the method that promises the easiest result, it also makes for ugly security holes and hard to track down bugs. I'd go with storing all the operators and their operations in a hash and then using that to calculate your operations:

    my %bin_cmp = { 'eq' => sub { my ($l,$r) = @_; $l eq $r }, 'ne' => sub { my ($l,$r) = @_; $l ne $r }, '>' => sub { my ($l,$r) = @_; $l < $r }, '<' => sub { my ($l,$r) = @_; $l > $r }, }; my $op = 'ne'; my $left = "Hello"; my $right = "World"; if (not exists $bin_cmp{$op}) { die "Don't know what to do with '$op'"; }; my $compare = $bin_cmp{$op}; my $result = $compare->($left, $right); print "$left $op $right is " . ($result ? 'true' : 'false');
Re: interpolating a variable into an operator
by Limbic~Region (Chancellor) on Jul 20, 2004 at 14:29 UTC
    mlhii,
    Without putting in a bit of extra effort, string eval is the way to go. This is typically considered evil since it is like an open invitation to let ghosts into the machine - and not all of them are Casper. Here is a contrived way to do the same sort of thing safer, but it is more work:
    #!/usr/bin/perl use strict; use warnings; my $eq_op = 'eq'; my $ne_op = 'ne'; my $foo = '1234'; my $bar = 'abcd'; my %compare = ( eq => \&eq_compare, ne => \&ne_compare, ); if ( $compare{ $eq_op }->($foo, $bar) ) { print "$foo and $bar are the same string\n"; } if ( $compare{ $ne_op }->($foo, $bar) ) { print "$foo and $bar are not the same string\n"; } sub eq_compare { return $_[0] eq $_[1] } sub ne_compare { return $_[0] ne $_[1] }

    Cheers - L~R

    On advice from Corion in a /msg, I removed the ternary operator from the sub's returns as they were not needed. Of course, with subs this small you could make them anonymous as he has. Hmmph - my Casper story is funnier though
Re: interpolating a variable into an operator
by Joost (Canon) on Jul 20, 2004 at 14:20 UTC
Re: interpolating a variable into an operator
by NetWallah (Canon) on Jul 20, 2004 at 15:48 UTC
    Corion and Limbic~Region have provided excellent options.

    Here is my offering, attempting to improve the readability. (Untested - this is just a concept):

    my %ops =( eq => sub{shift eq shift}, '==' => sub{shift == shift}, 'gt' => sub{shift > shift} ); sub compare{ my ($p1, $op, $p2) = @_; return $ops{$op}($p1, $p2); } # Now you can write stuff like if (compare('abc', 'eq', 'ABC'){ ..action }
    IMHO, keeping the operator in the middle of operands makes this more readable.

    Of course, there are other ways of doing this, using operator overloading, but I wouldnt go there for this simple case.

    Update7/22 Thanks, Anneq: deleted ampersand in front of &$ops... changed sub() to sub{}.

        Earth first! (We'll rob the other planets later)

Re: interpolating a variable into an operator
by davorg (Chancellor) on Jul 20, 2004 at 14:21 UTC

    You should probably look at "eval".

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: interpolating a variable into an operator
by Grygonos (Chaplain) on Jul 20, 2004 at 14:25 UTC

    An example script would help. but just by naked eye scan, I can see you are not using double =. In fact you should really use eq instead since you are doing character comparison. Secondly,this does not work to my knowledge(without the use of eval as noted above). You should get a scalar found where operator expected error. What are you trying to accomplish? Methods like this often indicate the need to rethink your design.

    Let us know what you're trying to accomplish, post what you've tried... and then maybe we can help.
Re: interpolating a variable into an operator
by jonadab (Parson) on Jul 20, 2004 at 18:48 UTC
    I am trying to store operators in a variable and then use the variable as the operator

    Lisp can do this; Perl cannot. It can, however, store an anonymous *subroutine* in a variable. This is syntactically different from an operator, but it can accomplish the same effect:

    $op = sub { $_[0] eq $_[1] }; if($op->($somvar, "some text")){ #do stuff }

    Resist the urge to use string eval for this.


    ;$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$;[-1]->();print
      Bah. We just need more people to treat perl like lisp. This isn't impossible - it is just difficult.