tags:

views:

108

answers:

2

See also: How is "0" result from readdir not false in a while condition?. (Not a duplicate; just closely related.)


Where in the documentation does it say that while tests readdir for definedness? For instance, this code

#!/usr/bin/perl

use strict;
use warnings;

opendir my $dir, "/tmp" or die "$!";

while (my $file = readdir($dir)) {
        print "$file\n";
}
closedir $dir;

when run through B::Deparse yields:

use warnings;
use strict 'refs';
die "$!" unless opendir my $dir, '/tmp';
while (defined(my $file = readdir $dir)) {
    do {
        print "$file\n"
    };
}
z.pl syntax OK

I expect this behaviour, but I cannot find where it is specified. In the I/O Operators section of perlop it says

The following lines are equivalent:

     while (defined($_ = <STDIN>)) { print; }
     while ($_ = <STDIN>) { print; }
     while (<STDIN>) { print; }
     for (;<STDIN>;) { print; }
     print while defined($_ = <STDIN>);
     print while ($_ = <STDIN>);
     print while <STDIN>;

But there is no mention of readdir.

+4  A: 

You're quite right about it being undocumented. I've looked rather hard, and I can't find any reference to it being special either. It is special, as you've discovered, and as demonstrated by:

$ perl -MO=Deparse \
       -E'opendir(my $dir, "."); while($_ = readdir($dir)) { say; }'

BEGIN {
    $^H{'feature_say'} = q(1);
    $^H{'feature_state'} = q(1);
    $^H{'feature_switch'} = q(1);
}
opendir my $dir, '.';
while (defined($_ = readdir $dir)) {
    say $_;
}
-e syntax OK

Looking through the source, Perl_newWHILEOP in op.c specifically has tests for readdir, glob, readline and each... Hmm, let's do some digging, and see when readdir was added.

A bit of digging with git reveals that it's been that way since at least 1998, with Gurusamy Sarathy making the relevant change in commit 55d729e4. While I haven't gone digging to see which releases that's gone into, I'd wager it would be at least 5.6.0 and above. I can't find any mention of it in the deltas.

It might be mentioned in the third edition camel book, but I haven't checked to find out.

I think that a patch here (or even just a note to p5p) would certainly be appreciated.

Paul

pjf
Interesting, glob in while does get tested for definedness, but bsd_glob in while does not. Looks like it is time for a document patch.
Chas. Owens
see also the counter example in my question, where you can fool Perl's DWIM logic if the call to readdir() is not directly in the while() loop but in a function called in the while() test.
Alnitak
A: 

perldoc perlop explains the implicit defined test in the while loop for in the context of readline.

Sinan Ünür
Yeah, but it says nothing about readdir or glob.
Chas. Owens
I know. However, knowing that both readdir and glob return undef when there is nothing left to return in scalar context and considering that the same DWIMery that enables while ( <$in> ) to do the right thing in that context would come in handy here as well might be helpful.
Sinan Ünür
Which is why that link was part of the original question. I even quoted from it. The issue isn't what is it doing, it is where is it documented. So no one can find documentation (apart from the code) that says this behavior exists or will continue to exist.
Chas. Owens