The subject says it almost all, really. In particular this has come out in another thread and the present node is much a duplicate of this one, but the matter was interesting enough to be meditated separately.

Now, we all know that while applies some magic when used with angular parens to improve its use as the Perl idiomatic iterator on filehandles:

$ perl -MO=Deparse -e 'while (<>) {}' while (defined($_ = <ARGV>)) { (); } -e syntax OK
and also (but less widely known):
$ perl -MO=Deparse -e 'while (my $line=<>) {}' while (defined(my $line = <ARGV>)) { (); } -e syntax OK
Now, we also know that the intepreter does its best applying some heuristics to decide whether those parens are meant to mean (no pun intended, heh!) readline or glob. But of course one most certainly wants the former within the clause of the while loop.

The point: however, what I've just unexpectedly found out is that the same magic applies also when the angular parens have the other meaning:

$ perl -MO=Deparse -e '@a=qw/a b c/; print while <@a>' @a = ('a', 'b', 'c'); use File::Glob (); print $_ while defined($_ = glob(join($", @a))); -e syntax OK
indeed:
$ perl -le '@a=qw/a b c/; print while <@a>' a b c
It appears to work, but is much more probable not to be what one would have meant in the first place. Thus it may mask a typo or a distraction, or more simply a cargo culted use, as it seems to me in the context where I saw this popping out.

So I wonder whether this is a (perhaps unavoidable) side-effect or if it is intentional, although I doubt about the latter possibility...

Replies are listed 'Best First'.
Re: C<while> magic also working with glob(): intentional or not?
by merlyn (Sage) on Sep 27, 2005 at 18:06 UTC
    @a=qw/a b c/; print while <@a>
    That's definitely code you don't want to be using in production. You're taking a list of items, joining them with whitespace (techically, with $" which makes this even more broken), then running the glob operator on them. That expands them as filenames, but of course uses the space delimiters to separate the names. Then, the resulting list is either returned in entirity (in a list context), or doled out one-by-one in a scalar context, as you have here.

    So, this is really really not the right way to walk through a list of items. It breaks when any of the following are true:

    • $" is not a single space
    • Any of the list items contain whitespace
    • Any of the list items are the empty string
    • Any of the list items are glob patterns (try this with * as one of the items)
    • The list is terminated early, so we end up reentering (the state of the doled-out list is maintained associated with the use of the glob)
    In fact, I'd say you got lucky on your choice of example!

    Definitely want to steer-far-clear of code like this.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

      ++merlyn for the detailed explanation.
      FYI, in the thread that spawned this one, we warned the code's author that the code is both wrong and scary.
      That's definitely code you don't want to be using in production
      Huh! Don't misunderstand me...

      That's definitely code I don't want to be using in any case.

      More precisely, as I thought I had clearly said in, this popped out here:

      while (<@dataarray>) { my @microdata;

      Now, when I saw this I was astonished and I doubted the author's claim that "it does do the job I require", as I would have expected it to fail outright.

      OTOH I do know what is happening here but I'd like to know why it happens, that is, to express myself perhaps not extremely precisely from the technical pov, but hopefully clearly enough why "perl adds a

      defined($_ =
      in front of glob".

      The point being, I would consider it more logical either not to add anything or even to yield an error or emit a warning...

Re: C<while> magic also working with glob(): intentional or not?
by Util (Priest) on Sep 27, 2005 at 18:39 UTC
    The exact heuristics may be helpful in this meditation. Quoting from the perlop section on I/O Operators:
    If what the angle brackets contain is a simple scalar variable (e.g., <$foo>), then that variable contains the name of the filehandle to input from, or its typeglob, or a reference to the same. For example:
    $fh = \*STDIN; $line = <$fh>;
    If what's within the angle brackets is neither a filehandle nor a simple scalar variable containing a filehandle name, typeglob, or typeglob reference, it is interpreted as a filename pattern to be globbed, and either a list of filenames or the next filename in the list is returned, depending on context. This distinction is determined on syntactic grounds alone. That means <$x> is always a readline() from an indirect handle, but <$hash{key}> is always a glob(). That's because $x is a simple scalar variable, but $hash{key} is not--it's a hash element.

    One level of double-quote interpretation is done first, but you can't say <$foo> because that's an indirect filehandle as explained in the previous paragraph.
      The exact heuristics may be helpful in this meditation. Quoting from the perlop section on I/O Operators:
      OTOH chester's observation, which comes completely unexpected to me, suggests that the observed behaviour may have little if anything to do with angular parens and thus that that heuristics may not be relevant at all.
Re: C<while> magic also working with glob(): intentional or not?
by chester (Hermit) on Sep 27, 2005 at 17:38 UTC
    It appears to add a defined even without angle brackets, if you use glob(). I don't know if this means anything.

    > perl -MO=Deparse -e "while(glob('*')){ print }" use File::Glob (); while (defined($_ = glob('*'))) { print $_; } -e syntax OK