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

Hello,

OK, I don't really want to read a file this way, but one of my colleagues was coding this and we can't figure out why there should be a problem reading from the filehandle in the middle of the foreach loop. If anybody can explain the reason please could you enlighten me?

Thanks.
use strict; use diagnostics; my $line = (<DATA>); print "line ouside loop = $line"; foreach $line (<DATA>) { print "line from foreach = $line"; $line = (<DATA>) or print "error reading filehandle\n"; $line ||= "null\n"; print "line inside loop = $line"; } __DATA__ 1 2 3 4 5

Replies are listed 'Best First'.
Re: Trying to read a filehandle inside a loop
by broquaint (Abbot) on Oct 23, 2002 at 09:11 UTC
    The diagnostics error is due to the fact that the reading of a file could return 0 which would evaluate to false in a boolean context, whereas you want to be testing for definedness. The reason you can't read from <DATA> within the loop is that you've already slurped it in the foreach. So in this case a while loop would make a lot more sense e.g
    use strict; use diagnostics; my $line = (<DATA>); print "line ouside loop = $line"; while(my $line = <DATA>) { print "line from foreach = $line"; $line = (<DATA>) or print "error reading filehandle\n"; $line ||= "null\n"; print "line inside loop = $line"; } __DATA__ 1 2 3 4 5

    HTH

    _________
    broquaint

      Thanks for your explanation. I can see now that the foreach has 'slurped' the data from the filehandle, so there is no data to read inside the loop. Why doesn't the 'while' loop slurp the data too? I'll have a look in perlsyn I think! Cheers.
        Why doesn't the 'while' loop slurp the data too?
        Because the filehandle is only evaulated in a scalar context, so you'll only get one line per iteration. Whereas a foreach loop evaluates the filehandle in a list context which produces the list which it iterates over. Another thing to be aware of is that if you're iterating over a filehandle in a while loop perl will auto-magically stick a defined test around your condition e.g
        while(my $line = <DATA>) # becomes while (defined(my $line = <DATA>))
        So now if a single 0 is read the loop will continue.
        HTH

        _________
        broquaint

Re: Trying to read a filehandle inside a loop
by gjb (Vicar) on Oct 23, 2002 at 09:20 UTC

    The foreach statement causes <DATA> to be evaluated in list context, hence all data is read at once. Subsequent reads obviously fail by lack of data.

    This is easy to see by replacing the foreach $line (<DATA>) { by while ($line = <DATA>) { which does what you expected.

    hope this helps, -gjb-

Re: Trying to read a filehandle inside a loop
by DapperDan (Pilgrim) on Oct 23, 2002 at 09:24 UTC
    while (my $foo = <BAR>) { # use $foo }

    is also much more idiomatic, which makes your code more readable to other perl programmers.