views:

292

answers:

1

See also: Where in the documentation does it say that while tests readdir for definedness?. (Not a duplicate; just closely related.)


Many people treat the loop below as idiomatic:

while (defined(my $file = readdir($dir)) {
    ...
}

instead of:

while (my $file = readdir($dir)) {
    ...
}

because supposedly with the latter version if the filename is just "0" (zero) it should terminate the loop, whereas it returns 'undef' when there are no more files.

However at some point in the past this test for defined() stopped being necessary - there appears to be special case code that allows the latter version to work regardless.

I'd like to know how this works?

Curiously,if I replace the call to readdir() with a call to foo() instead:

sub foo
{
    my ($dir) = @_;
    return readdir($dir);
}

while (my $file = foo($dir)) {
    ...
}

then the code does do what I'd expect, and terminate the loop when a file named "0" is found.

(tested with Perl 5.8.9 on MacOS X 10.5.6)

+8  A: 

It is magic. Specifically while magic (documented in perlsyn, perlop, and probably other places I don't remember). Perl allows you certain shorthand notations. If you want to see what Perl is doing behind your back you can use B::Deparse. Here is a file that uses the shorthand loop:

#!/usr/bin/perl

use strict;
use warnings;

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

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

If you run perl -MO=Deparse filename.pl you get the code Perl sees:

use warnings;
use strict 'refs';
die "$!" unless opendir my $dir, '/tmp';
while (defined(my $file = readdir $dir)) {
    do {
        print "$file\n"
    };
}
filename.pl syntax OK
Chas. Owens
+1 for B::Deparse - would be really helpful if someone can provide links to specific documentation. I can't find it in man perlsyn.
Alnitak
Click B::Deparse for docs on it, click on perlsyn to be taken to the section of perlsyn that documents the behaviour (look for "which is Perl short-hand for the more explicitly written version:"). There is better docs somewhere in there but I can't remember where.
Chas. Owens
Added a link to the perlop section that also covers this, but still no specific docs on why readdir gets the same treatment.
Chas. Owens
the perlop page was more useful than perlsyn, thanks.
Alnitak
In the section of perlsyn on 'for loops' it says:- Using readline (or the operator form, <EXPR> ) as the conditional of a for loop is shorthand for the following. This behaviour is the same as a while loop conditional. for ( prompt(); defined( $_ = <STDIN> ); prompt() ) { # do something }That's as near as I got to anything...I didn't find mention of readdir in perlop (or perlsyn).
Jonathan Leffler