His rationale was that if you have a line that's 0 (it'd have to be the last line, else it would have a carriage return) then your while would exit prematurely if you used my statement ($line would be set to "0", and the return value from the assignment would thus also be "0" which gets evaluated to false). If you check for defined-ness, then you don't run into this problem. It makes perfect sense.

So I tried it. I created a textfile whose last line is 0 with no carriage return on it. I ran it through my loop and the loop did not exit prematurely.

I then thought, "Aha, maybe the value isn't actually 0, maybe there's something else there that's screwing things up!" So I used Dump() from Devel::Peek and this is what it gave me:

That seems to tell me that the value is actually the string "0", as I get a similar result if I call Dump() on a scalar I've explicitly set to "0" (the only difference is in the LEN field -- from the file LEN is 80, whereas from the scalar LEN is 8).

So what's the deal? Why doesn't my while() loop exit prematurely if I pass it a line that's only "0" with no carriage return? Is Evan's loop actually more defensive, or does Perl do something crazy internally that means you don't need to worry about these things and while() actually only does exit when you hit eof?

This is why I wouldn't edit the meaning of someone's response (I only fix obvious typos). Add a comment instead if you think something is missing or could be improved upon. And kudos to you for investigating the internals!
–
EtherSep 22 '10 at 22:08

No -1, because I agree B::Deparse is useful for exploring what Perl is doing when you're stumped, but IMHO using it to "answer" a question like this is not... right. It only tells you what Perl will do in the handful of specific cases that you try it on, it doesn't tell you anything about the general conditions under which this behaviour will occur. Only the language spec can tell you that.
–
j_random_hackerSep 22 '10 at 23:02

4

@j_random_hacker, since perl5 does not have a formal language spec, the behavior of the interpreter IS the definative answer
–
Eric StromSep 23 '10 at 0:36

2

@j_random_hacker: In perl's defense, perl6 puts an end to that. There's a spec and there are several independent implementations to compare with. The spec is the final word
–
DaenythSep 23 '10 at 2:38

In scalar context, evaluating a filehandle in angle brackets yields the next line from that file (the newline, if any, included), or "undef" at end-of-file or on error. When $/ is set to "undef" (sometimes known as file-slurp mode) and the file is empty, it returns '' the first time, followed by "undef" subsequently.

Ordinarily you must assign the returned value to a variable, but there is one situation where an automatic assignment happens. If and only if the input symbol is the only thing inside the conditional of a "while" statement (even if disguised as a "for(;;)" loop), the value is automatically assigned to the global variable $_, destroying whatever was there previously. (This may seem like an odd thing to you, but you'll use the construct in almost every Perl script you write.) The $_ variable is not implicitly localized. You'll have to put a "local $_;" before the loop if you want that to happen.

In these loop constructs, the assigned value (whether assignment is automatic or explicit) is then tested to see whether it is defined. The defined test avoids problems where line has a string value that would be treated as false by Perl, for example a "" or a "0" with no trailing newline. If you really mean for such values to terminate the loop, they should be tested for explicitly:

Good answer so I deleted mine. But the Perl docs are misleading -- they say, "If and only if the input symbol is the only thing inside the conditional of a while statement" -- but later contradict the "and only if" part by showing that while (my $line = <STDIN>) also behaves the same way. Leaving us wondering about exactly which circumstances this DWIMmery will be performed in.
–
j_random_hackerSep 22 '10 at 23:05

1

@j_random: Isn't the "if and only if" part referring to whether $_ is used as the location for the line read from the handle, not whether the defined logic is employed?
–
EtherSep 22 '10 at 23:15

You're absolutely right, poor reading comprehension on my part. My apologies. I still think it wouldn't hurt to be explicit about exactly when define is auto-applied. My guess is: if the loop conditional test is <SOMETHING> or a scalar assignment with <SOMETHING> on the RHS -- is that everything though?
–
j_random_hackerSep 23 '10 at 1:37

@j_random: yes, I think that would be correct.
–
EtherSep 23 '10 at 2:14

While it is correct that the form of while (my $line=<$fh>) { ... } gets compiled to while (defined( my $line = <$fh> ) ) { ... } consider there are a variety of times when a legitimate read of the value "0" is misinterpreted if you do not have an explicit defined in the loop or testing the return of <>.

I am not saying these are good forms of Perl! I am saying that they are possible; especially Failure 3,4 and 5. Note the failure with no Perl warning on number 4 and 5. The first two have their own issues...