Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked

The "<" in the grep block

by vagabonding electron (Chaplain)
on Sep 23, 2012 at 14:56 UTC ( #995208=perlquestion: print w/replies, xml ) Need Help??
vagabonding electron has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,
doing some exercises from the Alpaca book I noticed a strange behavior of the grep operator.
The exercise was to filter the files smaller than 1000 bytes.
This code (if called with C:\perl\bin>perl N:/TEMP/*):
#!/usr/bin/perl -l use strict; use warnings; @ARGV = map{glob} @ARGV; my @selection = grep { -s < 1000 } @ARGV; print for @selection;
produces the following error message:
Warning: Use of "-s" without parentheses is ambiguous at lin +e 7. Unterminated <> operator at line 7.
If I use the parenthesis it runs ok:
#!/usr/bin/perl -l use strict; use warnings; @ARGV = map{glob} @ARGV; my @selection = grep { (-s) < 1000 } @ARGV; print for @selection;
If I search for files bigger than 1000 the parentheses are not necessary.
It seems that perl interprets the less than sign as a part of a diamond operator.
In the answers part of the book however there is a line exact as my original line without parentheses:
my @smaller_than_1000 = grep { -s < 1000 } @ARGV;
Is it the windows peculiarity which I have here?
Thanks in advance!

Replies are listed 'Best First'.
Re: The "<" in the grep block
by tobyink (Abbot) on Sep 23, 2012 at 15:12 UTC

    Certain Perl built-ins, including -s can take an argument or operate on the default variable $_. For example, defined $var versus just defined.

    In certain circumstances, perl needs a little help to disambiguate. In this case, it's not sure whether you mean an ill-formed glob:



    (-s) < 1000

    perl could theoretically look ahead searching for a ">" to disambiguate, but IIRC it only ever looks ahead one token.

    Other ways to disambiguate would be to use a different operator which suffers from fewer ambiguities:

    grep { 1000 > -s } @ARGV; # or grep { -s <= 999 } @ARGV;

    or to place parentheses like this:

    -s() < 1000

    or include an explicit $_:

    -s $_ < 1000

    This is not Windows specific. It could theoretically change between Perl releases, but the oldest and newest versions of Perl I have available on this computer (5.8.9 and 5.16.0) both behave the same with regard to this particular example. So I don't know why your book contains the bad example; perhaps the writer never actually tested it?

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: The "<" in the grep block
by Athanasius (Chancellor) on Sep 23, 2012 at 15:25 UTC

    To reinforce tobyink’s answer:

    Is it the windows peculiarity which I have here?

    No, with

    use strict; use warnings; use diagnostics;

    I get identical messages under cmd.exe (perl 5, version 16, subversion 0 (v5.16.0) built for MSWin32-x86-multi-thread-64int) and Cygwin (perl, v5.10.1 (*) built for i686-cygwin-thread-multi-64int):

    $ perl -c Warning: Use of "-s" without parentheses is ambiguous at l +ine 36 (#1) (S ambiguous) You wrote a unary operator followed by something tha +t looks like a binary operator that could also have been interpreted + as a term or unary operator. For instance, if you know that the rand function has a default argument of 1.0, and you write rand + 5; you may THINK you wrote the same thing as rand() + 5; but in actual fact, you got rand(+5); So put in parentheses to say what you really mean. Unterminated <> operator at line 36 (#2) (F) The lexer saw a left angle bracket in a place where it was exp +ecting a term, so it's looking for the corresponding right angle bracket, + and not finding it. Chances are you left some needed parentheses out earlier in the line, and you really meant a "less than". Uncaught exception from user code: Unterminated <> operator at line 36. at line 36
    If I search for files bigger than 1000 the parentheses are not necessary.

    I take it you mean:

    my @selection = grep { -s > 1000 } @ARGV;

    Here there is no ambiguity, since > doesn’t begin any other operator, as < does.

    Update: The following excerpt from -X may also be of (tangential) interest:

    These operators are exempt from the "looks like a function rule" described above. That is, an opening parenthesis after the operator does not affect how much of the following code constitutes the argument. Put the opening parentheses before the operator to separate it from code that follows (this applies only to operators with higher precedence than unary operators, of course):

    -s($file) + 1024 # probably wrong; same as -s($file + 1024) (-s $file) + 1024 # correct

    Hope that helps,

    Athanasius <°(((><contra mundum

Re: The "<" in the grep block
by NetWallah (Canon) on Sep 23, 2012 at 15:15 UTC
    I reproduced this issue on
    perl 5, version 14, subversion 2 (v5.14.2) built for x86_64-linux-gnu-thread-multi

    So it seems like this must have broken after the book was written. Sounds like a bug to me.

                 I hope life isn't a big joke, because I don't get it.

Re: The "<" in the grep block
by Marshall (Abbot) on Sep 23, 2012 at 16:36 UTC
    This statement seems odd to me:
    @ARGV = map{glob} @ARGV;
    glob what? map what? What did you intend for this statement to do?

      It does something analogous to the type of wild-card expansion that *nix shells do:

      @ARGV = '*.pl';; @ARGV = map{glob} @ARGV;; print for @ARGV;; ...

      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

      RIP Neil Armstrong

      This statement allows to use glob in cmd (Win32). Without this line the script if run as:
      C:\perl\bin>perl N:/TEMP/*
      throws the following message:
      Use of uninitialized value in numeric lt (<) at line 8. N:/TMP/*
      I have found this line by BrowserUK some time ago (cannot find the original node now) and I am very grateful for it.

      Update: Did not see the post from BrowserUK before I sent my message.

        I agree that

        @ARGV = map{glob} @ARGV; ....
        does work, however, I think since "glob" can do the expansion, why not use
        my @smaller_than_1000 = grep { -s $_ < 1000 } glob("@ARGV"); ....
        see glob for detail.

        If you tell me, I'll forget.
        If you show me, I'll remember.
        if you involve me, I'll understand.
        --- Author unknown to me
Re: The "<" in the grep block
by vagabonding electron (Chaplain) on Sep 23, 2012 at 17:27 UTC
    Thank you very much all of you!

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://995208]
Approved by McDarren
Front-paged by Corion
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (2)
As of 2018-07-21 10:18 GMT
Find Nodes?
    Voting Booth?
    It has been suggested to rename Perl 6 in order to boost its marketing potential. Which name would you prefer?

    Results (446 votes). Check out past polls.