Using Filehandle and while Loop Defined

While reading a book on advanced Perl programming (1), I came across this code:

while (defined($s = <>)) {
    ...

      

Is there any particular reason for using it defined

here? the documentation for perlop says:

In these loop constructs, the assigned value (whether the assignment is automatic or explicit) is then tested to determine if it is defined. a certain test avoids problems when a string has a string value that will be treated as false by Perl, such as a ""

or a "0"

new line without trailing. If you really want such values ​​to end the loop, they must be checked explicitly: [...]

So, would it be an angle or just because the book is too old and an automated test defined

was added to a recent version of Perl?


(1) Advanced Perl Programming, First Edition, by Sriram Srinivasan. O'Reilly (1997)

+3


source to share


3 answers


Perl has a lot of hidden behavior, much more than most other languages. Perl's motto is more than one thing, and because such latent behavior exists, there is often more than one way. Exactly the same thing.

/foo/

instead $_ =~ m/foo/

$x = shift

instead $x = shift @_

while (defined($_=<ARGV>))

instead while(<>)

and etc.

Which expressions to use mainly depends on your local coding standards and personal preference. More explicit expressions remind the reader of what's really going on under the hood. This can improve or improve the readability of your code - it depends on how knowledgeable the audience is and whether you are using well-known idioms.

In this case, the implicit behavior is a little more complicated than it sounds. Sometimes it perl

implicitly tests defined(...)

the result of a readline statement:

$ perl -MO=Deparse -e 'while($s=<>) { print $s }'
while (defined($s = <ARGV>)) {
    print $s;
}
-e syntax OK

      



but sometimes it won't:

$ perl -MO=Deparse -e 'if($s=<>) { print $s }'
if ($s = <ARGV>) {
    print $s;
}
-e syntax OK

$ perl -MO=Deparse -e 'while(some_condition() && ($s=<>)) { print $s }'
while (some_condition() and $s = <ARGV>) {
    print $s;
}
-e syntax OK

      

Let's assume you're worried about the corner cases that this implicit behavior should handle. Have you passed perlop

in memory so you know when Perl uses this implicit behavior and when it doesn't? Do you understand the differences in this behavior between Perl v5.14 and Perl v5.6? Do the people reading your code know?

Again, there is no right or wrong answer about when to use more explicit expressions, but the case of using explicit expressions is stronger when implicit behavior is more esoteric.

+8


source


Let's say you have the following file

4<LF>
3<LF>
2<LF>
1<LF>
0

      

( <LF>

represents a string. Note the absence of a newline on the last line.)

Let's say you are using the code

while ($s = <>) {
   chomp;
   say $s;
}

      

If Perl hadn't done anything magic, the output would have been

4
3
2
1

      

Note the absence 0

, since the string 0

is false. defined

necessary in the unlikely event that

  • You have a non-standard text file (trailing newline missing).
  • The last line of the file consists of one ASCII zero (0x30).



BUT WAIT FOR MINUTES! If you actually ran the above code with the above data, you will see it 0

printed! Many people don't know that Perl will automatically convert

while ($s = <>) {

      

to

while (defined($s = <>)) {

      

as shown here:

$ perl -MO=Deparse -e'while($s=<DATA>) {}'
while (defined($s = <DATA>)) {
    ();
}
__DATA__
-e syntax OK

      

So technically it doesn't even need to be specified defined

in this particular case.

However, I can't blame anyone for being explicit instead of relying on Perl to automatically modify their code. After all, Perl is (necessarily) quite specific about which code sequences it will change. Note the lack of defined

the following, although it is supposedly equivalent code:

$ perl -MO=Deparse -e'while((), $s=<DATA>) {}'
while ((), $s = <DATA>) {
    ();
}
__DATA__
-e syntax OK

      

+3


source


while($line=<DATA>){
    chomp($line);
if(***defined*** $line){
    print "SEE:$line\n";
}
}
__DATA__
1
0
3

      

Try the code with a specific remote and you will see a different result.

-2


source







All Articles