operator in a variable?

Discussion in 'Perl Misc' started by Michael Roper, Aug 22, 2003.

  1. Is it possible to store pieces of an expression in a variable that will get
    expanded before the larger expression is evaluated? For example, could I
    write something like: $result = $a $op $b; that would be evaluated as
    $result = $a + $b;? Thanks.

    Michael Roper
    Michael Roper, Aug 22, 2003
    #1
    1. Advertising

  2. Michael Roper

    Ted Zlatanov Guest

    On Fri, 22 Aug 2003, wrote:

    > my $result = eval "$x $op $y";
    > print $result;


    This won't work correctly for operators that modify either variable,
    because you interpolate $x and $y also; you probably want

    my $result = eval "\$x $op \$y";

    Ted
    Ted Zlatanov, Aug 22, 2003
    #2
    1. Advertising

  3. Michael Roper

    Ted Zlatanov Guest

    On 22 Aug 2003, wrote:

    > my %ops = ( '+' => sub {return $_[0] + $_[1]},
    > '-' => sub {return $_[0] - $_[1]},
    > );
    >
    > my $x = 123;
    > my $y = 456;
    >
    > for my $op ('+', '-') {
    > my $result = $ops{$op}($x, $y);
    > print "$x $op $y = $result\n";
    > }


    In case the operator needs to modify $x or $y, I would do it thus:

    $ops{'+'} = sub { my $xr = shift; my $yr = shift; return $$xr + $$yr; };

    my $result = $ops{$op}->(\$x, \$y);

    Ted
    Ted Zlatanov, Aug 22, 2003
    #3
  4. Ted Zlatanov <> writes:

    > On 22 Aug 2003, wrote:
    >
    > > my %ops = ( '+' => sub {return $_[0] + $_[1]},
    > > '-' => sub {return $_[0] - $_[1]},
    > > );
    > >
    > > my $x = 123;
    > > my $y = 456;
    > >
    > > for my $op ('+', '-') {
    > > my $result = $ops{$op}($x, $y);
    > > print "$x $op $y = $result\n";
    > > }

    >
    > In case the operator needs to modify $x or $y, I would do it thus:
    >
    > $ops{'+'} = sub { my $xr = shift; my $yr = shift; return $$xr + $$yr; };
    >
    > my $result = $ops{$op}->(\$x, \$y);


    That uglyness is quite unnecessary. The elements of @_ are _alaises_,
    not copies, of the aguments passed to a subroutine.

    --
    \\ ( )
    . _\\__[oo
    .__/ \\ /\@
    . l___\\
    # ll l\\
    ###LL LL\\
    Brian McCauley, Aug 22, 2003
    #4
  5. Michael Roper

    Sam Holden Guest

    On Fri, 22 Aug 2003 06:11:48 -0400, Ted Zlatanov <> wrote:
    > On 22 Aug 2003, wrote:
    >
    >> my %ops = ( '+' => sub {return $_[0] + $_[1]},
    >> '-' => sub {return $_[0] - $_[1]},
    >> );
    >>
    >> my $x = 123;
    >> my $y = 456;
    >>
    >> for my $op ('+', '-') {
    >> my $result = $ops{$op}($x, $y);
    >> print "$x $op $y = $result\n";
    >> }

    >
    > In case the operator needs to modify $x or $y, I would do it thus:
    >
    > $ops{'+'} = sub { my $xr = shift; my $yr = shift; return $$xr + $$yr; };
    >
    > my $result = $ops{$op}->(\$x, \$y);


    $ops{'+='} = sub {$_[0] += $_[1]};
    ($x, $y) = (123, 456);
    $ops{'+='}($x, $y);
    print "$x\n";

    Is the obvious example that shows you don't need to make the code
    unintuitive even if you want such things.

    --
    Sam Holden
    Sam Holden, Aug 22, 2003
    #5
  6. "Janek Schleicher" <> wrote in message news:<>...
    > Michael Roper wrote at Fri, 22 Aug 2003 01:54:20 -0700:
    >
    > > Is it possible to store pieces of an expression in a variable that will get
    > > expanded before the larger expression is evaluated? For example, could I


    > perldoc -f eval
    > my $result = eval "$x $op $y";
    > eval STRING is one of the things that you usually won't use unless you
    > really want to use it :)


    eval is not evil, only use it with caution.

    If something wrong happens running the code, the variable $@ will have
    the error string.

    my $result = eval "$x $op $y";
    if ($@) {
    # something was wrong ...
    warn $@; # will show the error
    # you can do something about it.
    }
    Francesc Guasch, Aug 22, 2003
    #6
  7. Janek Schleicher writes:
    > May I ask what the problem is you need to evaluate operators for.


    Sure, maybe that's for the best. :) I have tried eval and can't get
    anything to work. I need to modify a script that represents my one and only
    foray into Perl, it was done a year ago, and I'm sure there's a better way.
    (Also, any corrections to tortured terminology, concepts or usage on my part
    is appreciated. Whatever I learned a year ago is now fuzzy at best.)

    I'm starting with an ugly log generated by my server-side spam blocker. I
    use one script to nicely format that log and strip out any entry that is not
    a description of a blocked email. The result is a complete list of all
    blocked emails, with each record formatted as (in a fixed-width font):

    -----------------------------------------------------------------
    Date: 04.06.2003 07:42:43

    IP: 12.255.39.76
    Sender:
    Recipient:

    Response: 550 5.2.1 Mailbox unavailable.
    Reason: SPAMCOP [Spam Source, Various Others -- 127.0.0.2]
    Details: Blocked - see http://spamcop.net/bl.shtml?12.255.39.76

    Blacklist: www.spamcop.net
    Lookup: www.spamcop.net/w3m?action=checkblock&ip=12.255.39.76
    -----------------------------------------------------------------

    Because of the volume of blocked emails that need to be checked (for
    collateral damage), I wrote a second script that further strips out log
    records that are, for whatever reason, guaranteed to be spam and don't need
    to be manually confirmed.

    It's the second script I'm having trouble with. One of the main goals in
    writing it was to make it easy to manually add, modify, or delete (within
    the script itself) the "definitely spam" descriptions used to cull records
    from the log. For that, I use:

    my @aDelete =
    ({
    Name => 'open relay',
    Marker=> '^ Reason: (NJABL|OSIRUSOFT) \[Open Relay',
    Count => "0",
    },{
    Name => 'china and korea',
    Marker=> ' (china|korea) does not seem to care about spam$',
    Count => "0",
    });

    When I process the log, I check each log entry ($sLogRecord) against each
    Marker. If it's found, I increment the Count for the Marker. When I'm
    done, I use the Name and Count for each Marker to display a summary table of
    the results, as well as any log records that survived deletion (and
    therefore need to be checked as possible collateral damage):

    foreach $sLogRecord ( @aLogRecords )
    {

    #---------------------------------------------------------------------------
    -----------------#
    # compare against marker of each record type to be deleted

    #---------------------------------------------------------------------------
    -----------------#
    for( $i = 0; $i <= $#aDelete; $i++ )
    {
    if( $sLogRecord =~ /$aDelete[$i]->{Marker}/m )
    {
    $aDelete[$i]->{Count}++;
    $sLogRecord = undef;
    }
    }
    }

    This may be ugly, but it has worked well and I've been able to easily modify
    the entries in @aDelete as needed. The problem I have now is that for the
    first time I'd like to delete a record if it doesn't match a particular
    Marker. So, I'd like to add an entry to @aDelete such as:

    {
    Name => 'invalid recipient',
    Marker=> '^Recipient: michaelr@encraft\.com)$',
    Count => "0",
    }

    and then rather than:

    if( $sLogRecord =~ /$aDelete[$i]->{Marker}/m )

    do this instead:

    if( $sLogRecord !~ /$aDelete[$i]->{Marker}/m )

    It seemed to me that the cleanest way to do this was to include the desired
    operator in the @aDelete entry itself:

    my @aDelete =
    ({
    Name => 'invalid recipient',
    Marker=> '^Recipient: michaelr@encraft\.com)$',
    Op => "!~",
    Count => "0",
    },{
    Name => 'open relay',
    Marker=> '^ Reason: (NJABL|OSIRUSOFT) \[Open Relay',
    Op => "=~",
    Count => "0",
    },{
    Name => 'china and korea',
    Marker=> ' (china|korea) does not seem to care about spam$',
    Op => "=~",
    Count => "0",
    });

    But I have been unable to find a way to then write:

    if( $sLogRecord $aDelete[$i]->{Op} /$aDelete[$i]->{Marker}/m )

    that will work in the intended fashion. I have tried every permutation of
    eval I can think of.

    I realize that I can solve this problem in other ways. It's just that the
    only solutions I've come up with are pretty ugly. Any thoughts much
    appreciated.

    Michael Roper
    Michael Roper, Aug 22, 2003
    #7
  8. Michael Roper

    Uri Guttman Guest

    >>>>> "FG" == Francesc Guasch <> writes:

    >> perldoc -f eval
    >> my $result = eval "$x $op $y";
    >> eval STRING is one of the things that you usually won't use unless you
    >> really want to use it :)


    FG> eval is not evil, only use it with caution.

    no, only use eval when is does something that is much harder (or
    impossible) to do in other ways. caution is too light a word especially
    when newbies are asking about eval. almost all eval uses by newbies can
    be done with better and safer with hashes, code refs, dispatch tables,
    etc.

    the point is that eval is a last resort and not the first technique to
    try. it is very rarely needed and used way too often. so the 'dogma'
    here is to never support its use unless you have a clear understanding
    of what it does, how it can be unsafe and a very strong reason why it is
    the best solution.

    uri

    --
    Uri Guttman ------ -------- http://www.stemsystems.com
    --Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
    Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
    Uri Guttman, Aug 22, 2003
    #8
  9. Uri Guttman <> wrote:
    >>>>>> "FG" == Francesc Guasch <> writes:

    >


    > >> my $result = eval "$x $op $y";


    > FG> eval is not evil, only use it with caution.
    >
    > no, only use eval when is does something that is much harder (or
    > impossible) to do in other ways. caution is too light a word especially
    > when newbies are asking about eval. almost all eval uses by newbies can
    > be done with better and safer with hashes, code refs, dispatch tables,
    > etc.



    For those of you following along at home, you should note that
    what is being discussed here is the "eval EXPR" form.

    "eval BLOCK" is not evil.


    --
    Tad McClellan SGML consulting
    Perl programming
    Fort Worth, Texas
    Tad McClellan, Aug 22, 2003
    #9
  10. Michael Roper wrote:
    >
    > Janek Schleicher writes:
    > > May I ask what the problem is you need to evaluate operators for.

    >
    > Sure, maybe that's for the best. :) I have tried eval and can't get
    > anything to work. I need to modify a script that represents my one and only
    > foray into Perl, it was done a year ago, and I'm sure there's a better way.
    > (Also, any corrections to tortured terminology, concepts or usage on my part
    > is appreciated. Whatever I learned a year ago is now fuzzy at best.)
    >
    > I'm starting with an ugly log generated by my server-side spam blocker. I
    > use one script to nicely format that log and strip out any entry that is not
    > a description of a blocked email. The result is a complete list of all
    > blocked emails, with each record formatted as (in a fixed-width font):
    >
    > -----------------------------------------------------------------
    > Date: 04.06.2003 07:42:43
    >
    > IP: 12.255.39.76
    > Sender:
    > Recipient:
    >
    > Response: 550 5.2.1 Mailbox unavailable.
    > Reason: SPAMCOP [Spam Source, Various Others -- 127.0.0.2]
    > Details: Blocked - see http://spamcop.net/bl.shtml?12.255.39.76
    >
    > Blacklist: www.spamcop.net
    > Lookup: www.spamcop.net/w3m?action=checkblock&ip=12.255.39.76
    > -----------------------------------------------------------------
    >
    > Because of the volume of blocked emails that need to be checked (for
    > collateral damage), I wrote a second script that further strips out log
    > records that are, for whatever reason, guaranteed to be spam and don't need
    > to be manually confirmed.
    >
    > It's the second script I'm having trouble with. One of the main goals in
    > writing it was to make it easy to manually add, modify, or delete (within
    > the script itself) the "definitely spam" descriptions used to cull records
    > from the log. For that, I use:
    >
    > my @aDelete =
    > ({
    > Name => 'open relay',
    > Marker=> '^ Reason: (NJABL|OSIRUSOFT) \[Open Relay',
    > Count => "0",
    > },{
    > Name => 'china and korea',
    > Marker=> ' (china|korea) does not seem to care about spam$',
    > Count => "0",
    > });
    >
    > When I process the log, I check each log entry ($sLogRecord) against each
    > Marker. If it's found, I increment the Count for the Marker. When I'm
    > done, I use the Name and Count for each Marker to display a summary table of
    > the results, as well as any log records that survived deletion (and
    > therefore need to be checked as possible collateral damage):
    >
    > foreach $sLogRecord ( @aLogRecords )
    > {
    >
    > #---------------------------------------------------------------------------
    > -----------------#
    > # compare against marker of each record type to be deleted
    >
    > #---------------------------------------------------------------------------
    > -----------------#
    > for( $i = 0; $i <= $#aDelete; $i++ )
    > {
    > if( $sLogRecord =~ /$aDelete[$i]->{Marker}/m )
    > {
    > $aDelete[$i]->{Count}++;
    > $sLogRecord = undef;
    > }
    > }
    > }
    >
    > This may be ugly, but it has worked well and I've been able to easily modify
    > the entries in @aDelete as needed. The problem I have now is that for the
    > first time I'd like to delete a record if it doesn't match a particular
    > Marker. So, I'd like to add an entry to @aDelete such as:
    >
    > {
    > Name => 'invalid recipient',
    > Marker=> '^Recipient: michaelr@encraft\.com)$',
    > Count => "0",
    > }
    >
    > and then rather than:
    >
    > if( $sLogRecord =~ /$aDelete[$i]->{Marker}/m )
    >
    > do this instead:
    >
    > if( $sLogRecord !~ /$aDelete[$i]->{Marker}/m )
    >
    > It seemed to me that the cleanest way to do this was to include the desired
    > operator in the @aDelete entry itself:
    >
    > my @aDelete =
    > ({
    > Name => 'invalid recipient',
    > Marker=> '^Recipient: michaelr@encraft\.com)$',
    > Op => "!~",
    > Count => "0",
    > },{
    > Name => 'open relay',
    > Marker=> '^ Reason: (NJABL|OSIRUSOFT) \[Open Relay',
    > Op => "=~",
    > Count => "0",
    > },{
    > Name => 'china and korea',
    > Marker=> ' (china|korea) does not seem to care about spam$',
    > Op => "=~",
    > Count => "0",
    > });
    >
    > But I have been unable to find a way to then write:
    >
    > if( $sLogRecord $aDelete[$i]->{Op} /$aDelete[$i]->{Marker}/m )
    >
    > that will work in the intended fashion. I have tried every permutation of
    > eval I can think of.


    Combine that with someone's prior suggestion involving
    using functions for the operators. Put the FUNCTION NAME
    in your "Op" entry and call that function to perform the
    operation needed.

    Mike
    Michael P. Broida, Aug 22, 2003
    #10
  11. Uri Guttman <> writes:
    >>>>>> "MPB" == Michael P Broida <> writes:

    > MPB> Combine that with someone's prior suggestion involving
    > MPB> using functions for the operators. Put the FUNCTION NAME
    > MPB> in your "Op" entry and call that function to perform the
    > MPB> operation needed.
    >
    > and that is getting back to symrefs which are bad.


    A way of doing the same thing that doesn't require symrefs is to use
    a hash of subrefs:

    my %funcHs = ( '+' => sub { $_[0] + $_[1] },
    '-' => sub { $_[0] - $_[1] },
    '*' => sub { $_[0] * $_[1] },
    '/' => sub { $_[0] / $_[1] } );

    Then call it like so:

    my $op = '+';
    print $funcHs{$op}->(1, 2), "\n";

    -=Eric
    --
    Come to think of it, there are already a million monkeys on a million
    typewriters, and Usenet is NOTHING like Shakespeare.
    -- Blair Houghton.
    Eric Schwartz, Aug 22, 2003
    #11
  12. Michael Roper

    Uri Guttman Guest

    >>>>> "ES" == Eric Schwartz <> writes:

    ES> Uri Guttman <> writes:
    >>>>>>> "MPB" == Michael P Broida <> writes:

    MPB> Combine that with someone's prior suggestion involving
    MPB> using functions for the operators. Put the FUNCTION NAME
    MPB> in your "Op" entry and call that function to perform the
    MPB> operation needed.
    >>
    >> and that is getting back to symrefs which are bad.


    ES> A way of doing the same thing that doesn't require symrefs is to use
    ES> a hash of subrefs:

    ES> my %funcHs = ( '+' => sub { $_[0] + $_[1] },
    ES> '-' => sub { $_[0] - $_[1] },
    ES> '*' => sub { $_[0] * $_[1] },
    ES> '/' => sub { $_[0] / $_[1] } );

    full circle. did you even see sam holden's post with the same solution?
    the reason i posted was to stop the thread from going back to
    symrefs. the code ref solution was shown and discussed already.

    uri

    --
    Uri Guttman ------ -------- http://www.stemsystems.com
    --Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
    Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
    Uri Guttman, Aug 23, 2003
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jakob Bieling

    Q: operator void* or operator bool?

    Jakob Bieling, Mar 5, 2004, in forum: C++
    Replies:
    2
    Views:
    563
    Rob Williscroft
    Mar 5, 2004
  2. John Smith
    Replies:
    2
    Views:
    415
    Ivan Vecerina
    Oct 6, 2004
  3. Alex Vinokur
    Replies:
    4
    Views:
    3,035
    Peter Koch Larsen
    Nov 26, 2004
  4. mfglinux
    Replies:
    11
    Views:
    687
    Roberto Bonvallet
    Sep 12, 2007
  5. David Filmer
    Replies:
    19
    Views:
    227
    Kevin Collins
    May 21, 2004
Loading...

Share This Page