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:
    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 whileis 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 whileshould 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:
        while (defined($_ = )) { print; }
        while ($_ = ) { print; }
        while () { print; }
        for (;;) { print; }
        print while defined($_ = );
        print while ($_ = );
        print while ;
    And this line of code works in a similar way, but without using $ _:
        while (my $line = ) { print $line }
    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 (($_ = ) ne '0') { ... }
        while () { last unless $_; ... }
    In other expressions with a Boolean context , a warning will be displayed when using if there is no explicit function call definedor comparison operation, provided that the pragma is enabled use warningsor the command line parameter -w(or variable $^W) is used.
    Thus, inside a loop, whilereading from a file automatically turns into a check for defined. However, you should replace it whilewith ifor even just complicate the condition of the loop by adding through andor orsome other subexpression, likethe 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 -w.

    Also popular now: