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

Greetings Monks,

I've recently come across this slightly odd (at least it seems so to me) construct: foreach my $line(<INFILE>){} # assume INFILE is open and I am a little curious - is this completely analagous to while (my $line = <INFILE>){} or is there some subtle difference? (in terms of efficiency)

Please shed the light of wisdom on this monk, unfamiliar with the mysteries of perl's inner workings.

Replies are listed 'Best First'.
Re: foreach question
by hv (Prior) on Feb 25, 2003 at 02:19 UTC

    The actions will be much the same, but the way it works is rather different: foreach takes a list, which means that before the loop starts the whole of the input file is read, building a list of lines on perl's internal stack and then iterating over that list.

    while, on the other hand, reads one line at a time and performs the block on that line before reading the next line. This can use far less memory, and so is usually preferable.

    Hugo
Re: foreach question
by Zaxo (Archbishop) on Feb 25, 2003 at 02:20 UTC

    Good question. foreach my $line(<INFILE>){} reads the entire file into an anonymous array, aliasing each element in turn to $line. while (my $line = <INFILE>){} reads the file one line at a time, storing each in turn in $line.

    The foreach version must allocate more memory than the while loop, which is a bit slower. The tradeoff is up to you.

    Update: ++chromatic points out that foreach iterates over a list, not an anonymous array.

    After Compline,
    Zaxo

      Thanks, I suspected as much, but wanted to make sure. In the code, the loop actually just appends $line to a string, so I suspect the effect of the foreach is not what the author had in mind.
        That's what people call a 'slurp'. There's many ways to do it and if you search PerlMonks for 'slurp' you'll find them. Here's one I cooked up earlier:
        # FILE is already open ... { local $/ = undef; $slurp = <FILE>; }
        Much better (and faster) than using joins, or loops to append. Keep it inside the {} block so that the change to $/ is only temporary. (also see $/ at perldoc). The file's entire content ends up in $slurp.
Re: foreach question
by OM_Zen (Scribe) on Feb 25, 2003 at 03:24 UTC
    Hi ,

    The script with a while to read is :

    #!perl use strict; my $ln = 9; my $contents; open (Fnm , "a.dat"); while ($contents = <Fnm>){ chomp; if ($ln == 9){ close Fnm; $ln = 0; } print "[ $contents ]\n"; } __END__ [ one ]


    The line that shows is just the first one after closing the contents at the start of the loop

    The script with the foreach to read is :
    #!perl use strict; my $ln = 9; my $contents; foreach $contents(<Fnm>){ chomp; if ($ln == 9){ close Fnm; $ln = 0; } print "[ $contents ]\n"; } __END__ [ one ] [ next ] [ next ] [ next ] [ next ]


    The line that shows is all in the data , even if one closes the file at the start of the foreach , cause the contents are first stored in an anonymous array and then read from that array and hence the foreach is not that one uses to read large chunk of data