📜 ⬆️ ⬇️

This mysterious while ...

“All the needs are incorporated in it, which only happen in the world. And it can satisfy all these needs. With the help of our science, of course. "
A. and B. Strugatsky

I think many of the Perl programmers are familiar with the following construction of line-by-line reading of the file contents:
while (<FILE>) {
# do something
}
This code has become so familiar that many do not even think about it, but how does it actually work? In this article I will describe one feature, which is very useful to remember.

As you know, a while is executed while its condition is true. However, in our case, the condition is a string that gives a boolean truth only if it is not:
a) undef ;
b) empty line;
c) a string containing a single character "0" .
What happens when a blank line suddenly appears in a file? Does the cycle really stop working? By no means. The read lines include the end-of-line marker, which means that the empty string is not actually empty, but "\n" , and therefore will be regarded in the boolean context as true. The same applies to the case when the file contains a line with only one character "0" . But there is a case when this rule does not work: if the last line of the file contains only the character "0" and does not end with a new line character. As a result, when reading this last line, we get the string "0" , which for while should be considered false, and, therefore, this line will not be processed. Right? It would seem that everything is correct, and now we must urgently grab either a favorite text editor, or validol, or both at the same time, depending on the degree of importance of the project where this code was used.

You can take your time: the code is absolutely correct and will work correctly, and this is due to the tricky feature of the while operator. I quote perlop ( loosely translated):
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>;
And this line of code works in a similar way, but without using $ _:
while ( my $line = <STDIN>) { print $line }
In all of these constructs, the assigned value (regardless of whether the assignment was explicit or not) checks whether the value is determined. This avoids the problem when the string value is false in a boolean context, for example, "" or "0" without the terminating newline character. If you intentionally want to use these values ​​to complete a loop, you need to check them explicitly:
while (($_ = <STDIN>) ne '0') { ... }
while (<STDIN>) { last unless $_; ... }
In other expressions with a boolean context, a warning will be displayed using the <filehandle> if there is no explicit call to the defined function or a comparison operation, provided that the use warnings pragma is use warnings or the -w command line parameter (or $^W variable) is used.
Thus, inside a while reading from a file automatically turns into a check on the defined . However, you should replace while with if or even just complicate the loop condition by adding a sub expression through and or or like the carriage turns into a pumpkin the operator loses all his magical qualities and begins to check the conditions strictly in accordance with the rules of type conversion. What the Perl compiler will tell us immediately, unless, of course, you forget to ask it with the -w .

')

Source: https://habr.com/ru/post/84762/


All Articles