开发者

In Perl, why does the `while(<HANDLE>) {...}` construct not localize `$_`?

开发者 https://www.devze.com 2023-02-20 22:43 出处:网络
What was the design (or technical) reason for Perl not automatically localizing $_ with the following syntax:

What was the design (or technical) reason for Perl not automatically localizing $_ with the following syntax:

while (<HANDLE>) {...}

Which gets rewritten as:

while (defined( $_ = <HANDLE> )) {...}

All of the other constructs that implicitly write to $_ do so in a localized manner (for/foreach, map, grep), but with while, you must explicitly localize the variable:

local $_;
while (<HANDLE>) {...}

My guess is that it has something to do with using Perl in "Super-AWK" mode with command line switches, but that might be wrong.

So if anyone knows (or better yet was involved in the language design discussion), could you share with us the reasoning behind this behavior? More specifically, why was allowing the value of $_ to persist outside of the loop deemed important, despite the bugs it can cause (which I tend to see all over the place on SO and in othe开发者_如何学Pythonr Perl code)?


In case it is not clear from the above, the reason why $_ must be localized with while is shown in this example:

sub read_handle {
    while (<HANDLE>) { ... }
}

for (1 .. 10) {
     print "$_: \n"; # works, prints a number from 1 .. 10
     read_handle;
     print "done with $_\n";  # does not work, prints the last line read from
                              # HANDLE or undef if the file was finished
}


From the thread on perlmonks.org:

There is a difference between foreach and while because they are two totally different things. foreach always assigns to a variable when looping over a list, while while normally doesn't. It's just that while (<>) is an exception and only when there's a single diamond operator there's an implicit assignment to $_.

And also:

One possible reason for why while(<>) does not implicitly localize $_ as part of its magic is that sometimes you want to access the last value of $_ outside the loop.


Quite simply, while never localises. No variable is associated with a while construct, so it doesn't have even have anything to localise.

If you change some variable in the while loop expression or in a while loop body, it's your responsibility to adequately scope it.


Speculation: Because for and foreach are iterators and loop over values, while while operates on a condition. In the case of while (<FH>) the condition is that data was read from the file. The <FH> is what writes to $_, not the while. The implicit defined() test is just an affordance to prevent naive code from terminating the loop on a read of false value.

For other forms of while loops, e.g. while (/foo/) you wouldn't want to localize $_.

While I agree that it would be nice if while (<FH>) localized $_, it would have to be a very special case, which could cause other problems with recognizing when to trigger it and when not to, much like the rules for <EXPR> distinguishing being a handle read or a call to glob.


As a side note, we only write while(<$fh>) because Perl doesn't have real iterators. If Perl had proper iterators, <$fh> would return one. for would use that to iterate a line at a time rather than slurping the whole file into an array. There would be no need for while(<$fh>) or the special cases associated with it.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号