
This mysterious while ...
“All the needs are inherent in him, which are just in the world. And he 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 reading the contents of a file line by line:
As you know, a loop
a)
b) an empty string;
c) a string containing a single character
What happens when an empty line suddenly appears in a file? Is the cycle going to stop working? Not at all. The read lines include the end of line marker, which means the empty line is actually not empty, but
You can take your time: the code is absolutely correct and will work correctly, and this is due to the tricky feature of the operator
the carriage turns into a pumpkinthe operator loses all its magical qualities and begins to check 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 him about it with the key
A. and B. Strugatsky
I think many of the Perl programmers are familiar with the following construction of reading the contents of a file line by line:
while () {
# do something
}
This code has become so familiar that many do not even think about how it actually works. In this article, I will describe one feature that is very useful to remember. As you know, a loop
while
is executed as long as its condition is true. However, in our case, a string is specified as a condition, which gives Boolean truth only if it is not: a)
undef
; b) an empty string;
c) a string containing a single character
"0"
. What happens when an empty line suddenly appears in a file? Is the cycle going to stop working? Not at all. The read lines include the end of line marker, which means the empty line is actually not empty, but
"\n"
, and therefore will be regarded in the Boolean context as true. The same applies to the case when a line with only one character appears in the file "0"
. But there is a case when this rule does not work: if the last line of the file contains only a character "0"
and does not end with a newline character. As a result, when reading this last line, we get a line "0"
that while
should be considered false, and therefore this line will not be processed. Right? It would seem that everything is correct, and now you urgently need to grab either your favorite text editor, or validol, or both at the same time, depending on the 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 operator
while
. I quote perlop (in free translation):The lines below are equivalent:Thus, inside a loop,And this line of code works in a similar way, but without using $ _:while (defined($_ =
)) { print; }
while ($_ =) { print; }
while () { print; }
for (;;) { print; }
print while defined($_ =);
print while ($_ =);
print while; In all of these constructions, for the assigned value (regardless of whether the assignment was explicit or not), a check is made to see if the value is defined. This avoids the problem when a string value is false in a Boolean context, for example, "" or "0" without a trailing newline character. If you intentionally want to use these values to complete the loop, you must check them explicitly:while (my $line =
) { print $line } In other expressions with a Boolean contextwhile (($_ =
) ne '0') { ... }
while () { last unless $_; ... } , a warning will be displayed when using if there is no explicit function call
defined
or comparison operation, provided that the pragma is enableduse warnings
or the command line parameter-w
(or variable$^W
) is used.
while
reading from a file automatically turns into a check for defined
. However, you should replace it while
with if
or even just complicate the condition of the loop by adding through and
or or
some other subexpression, like-w
.