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

Hi all,

Tis late on POETS day and not untypically, I've encountered a problem - which is a seeming oddity in the behaviour of grep - let me explain (which, if I don't, won't win me any friends;-)

There's something odd in the way that grep is behaving in the following...

grep /\Q$choice\E/, @REPORT && do { last READ_LOOP; };
Irrespective of the values of $choice and @REPORT, the last statement is always reached (and executed).

However, if the statement is re-written slightly - to add parenthesis for the arguments to the call to grep:

grep(/\Q$choice\E/, @REPORT) && do { last READ_LOOP; };
All of a sudden, the last statement is conditionally reached i.e. is now dependent on the values of $choice and @REPORT. For information, $choice typically contains either a path or a digit but, as was said in Airplane, that's not important right now:-)

B::Deparse provides further information:

user@unforgiven:~$ perl -MO=Deparse -e 'grep /\Q$choice\E/, @REPORT && + do { last READ_LOOP; };' grep /\Q$choice\E/, @REPORT && do { last READ_LOOP }; -e syntax OK user@unforgiven:~$ perl -MO=Deparse -e 'grep( /\Q$choice\E/, @REPORT) +&& do { last READ_LOOP; };' if (grep /\Q$choice\E/, @REPORT) { last READ_LOOP; } -e syntax OK
Armed with this information, I still can't see why perl interprets the 2 non-equivalently.

I'm sure this is but a small copse, but still I can't see the wood for the trees ... would anyone be good enough to enlighten me ?

TIA ,

A user level that continues to overstate my experience :-))

Replies are listed 'Best First'.
Re: Alas poor grep, I thought I knew him well..
by kennethk (Abbot) on May 08, 2009 at 15:11 UTC
    Like so much in life, it all depends on operator precedence. In the first case, your && binds more tightly to @REPORT than grep does. This means that as long as @REPORT is true in scalar context (i.e. is not an empty list), the && executes your do block. By adding parenthesis, you clarify the intended precedence and grep gets fed @REPORT and not the presumed return of your do block (which would never return because of your last).

    Update: For the technical correctness, the && operator is higher precedence than the , operator (Comma Operator), which creates generates the list fed into grep. Thus swapping && to the low precedence and fixes the issue.

      TFT kennethk - once again you've come up trumps.

      I'll be able to sleep now...

      A user level that continues to overstate my experience :-))
Re: Alas poor grep, I thought I knew him well..
by ikegami (Patriarch) on May 08, 2009 at 15:14 UTC

    Irrespective of the values of $choice and @REPORT, the last statement is always reached (and executed).

    I doubt that. I think you'll find the number of elements in @REPORT matters, since

    grep /\Q$choice\E/, @REPORT && do { last READ_LOOP; };

    means

    grep /\Q$choice\E/, ( @REPORT && do { last READ_LOOP; } );

    && has higher precedence than the list comma.

    Deparse's -p option would have helped you.

    >perl -MO=Deparse,-p -e"grep /\Q$choice\E/, @REPORT && do { last READ_ +LOOP; };" grep(/\Q$choice\E/, (@REPORT && do { last READ_LOOP })); -e syntax OK

    Parens can be used to disambiguate, and switching to using and will given you the precedence you desire. I also removed the do since it's useless here.

    grep(/\Q$choice\E/, @REPORT) # OK && last READ_LOOP;
    grep /\Q$choice\E/, @REPORT # OK and last READ_LOOP;
    grep(/\Q$choice\E/, @REPORT) # OK and last READ_LOOP;
      The above code looks fine to me. But in this sort of case, I would have used an "if" statement to, in my opinion, further clarify things, this is a matter of sytle:
      if (grep {/\Q$choice\E/}@REPORT) { last READ_LOOP; }
      I don't know the whole loop structure, but as a matter of style, I would have put the ending condition up in the while(..) or whatever loop if practical.

      I agree with ikegami, why be stingy with ()? They are super cheap (insignificant compile difference) and make things clear.