Introduction

The body of the loop (the STATEMENT or BLOCK) is repeatedly executed as long as the condition is true. In Perl, a scalar is false if it is equal, as a string, to either "" or "0". Otherwise it's true. (The undefined value undef has a string value of "", so undef is false.)

But this being Perl, that's not the end of it. Overloading causes one complication, but that's a story for another day. When you're processing a text file, you will often use a loop like this:

The problem might come if the file has a line which is blank, or just "0". Ordinarily that wouldn't matter, because the line would be terminated with "\n". So the value of $line would be "\n" or "0\n", which are both true. But what if it's the last line of the file, and it isn't terminated with a newline? Or what if you used the -l command-line switch to perl, which tells it to remove the line terminator automatically? We have to think about these things. The loop condition will then be false, and the loop will terminate before the file's been completely read.

Or will it? Actually, no. Perl is one step ahead, as usual. If Perl sees a loop like the one above, then it will secretly transform it into:

There is one other kind of loop which gets the same magic treatment, and that's if you use the glob operator. The glob operator returns the names of all the files which match a particular wildcard pattern: for example, you can print the names of all the Perl modules in the current directory like this:

I looked into the source code for perl, and I found a mistake in the code which was testing for that kind of condition. (The code was wrongly checking for a NULL opcode rather than a GLOB opcode.) I wrote up the correction as a patch, and sent it to the perl development mailing list, perl5-porters.

Interesting - is there any situation in which that test could have
succeeded, and so tested definedness when it should have tested truth?

This is starting to get confusing... Let me try and sum up the story up to this point:

In some situations, perl magically puts a defined(...) test around the condition in a while loop.

But the magic wasn't always working properly.

The reason it wasn't working is that there was a mistake in the perl source code...

... meaning that a different condition was being checked for.
(Instead of checking for a GLOB opcode, it was checking for a NULL opcode)

What Hugo asked was whether that condition could ever arise. The question surprised me: I hadn't even considered the possibility of it. So I thought a bit, and poked around a bit, and I realised that the answer was "yes". It can happen!

I won't go too deep into the details, because I don't want this post to turn into a book on the internals of perl. But I'll tell you what I found.

The new bug

I found that the broken condition is triggered by an assignment statement which has a logical operator on its right-hand side. For example,

Very nice explanation. Perhaps I should fill in the details leading up to my original post:

While rereading Effective Perl Programming I noticed that it warned against constructs such as: while($line = <FILE>) and recommended using while(defined($line = <FILE>)) instead. The book is several years old ('97 I think??) and I knew that this particular issue had been dealt with in later versions of perl. I had also noticed a "real" erratum in the book and decided to track down the books errata page so I could keep track of such things as I read the book.

Well, it turns out that I couldn't find a list of errata... The best I could come up with was this empty page
which looks lilke it should contain a list of errata but it doesnt. A one line '* this issue has been fixed in later versions' would have ended the story right there.

I then went looking for the documentation covering this automatic definedness feature. The trivial 'perldoc -f while' doesn't work, because while isn't a function. 'perldoc -q while | grep defined' didn't turn up anything, and searching for 'while and defined' over at perldoc.com or Super Search turned up way too much. I checked a few online docs around here, including perlop to no avail. It turns out that perlop is so long, the Monastery's copy is split in two... the info I was looking for was on the second page of perlop which would have ended my search had I found it.

Fine, the docs had failed me... I'd just have to figure it out on my own. B::Deparse to the rescue! After deparsing a dozen constructs, I was more confused than ever... <FILEHANDLE> seemed well behaved, I could make a few conclusions about how it would play with definedness and while. However, globbing didn't seem to play by the same rules. Sometimes it added the defined() sometimes it didn't. Hindsight shows that there was really only one case that didn't play nicely, but at the time it confused the hell out of me.

Frustrated, I posted to perlmonks, and the rest is covered quite nicely above.

But now your meditation has made me curious about the
origin of the bug you found. Was the implied-defined()
feature broken from the beginning -- which
seems unlikely -- or was it broken later and nobody noticed,
and if so, how and when?

The automatic implied defined()
was added after my time as pumpking. When I discovered
the danger of while (<>) {}, I didn't feel I
could change the language without breaking things,
so I added a warning instead.
That warning was unsatisfactory to a lot of people, so
the issue came up again, this time during one of Larry's
more available periods. Somebody proposed the language
change we have today, Larry OK'd it, and the patch was
installed almost immediately.

When putting a smiley right before a closing parenthesis, do you:

Use two parentheses: (Like this: :) )
Use one parenthesis: (Like this: :)
Reverse direction of the smiley: (Like this: (: )
Use angle/square brackets instead of parentheses
Use C-style commenting to set the smiley off from the closing parenthesis
Make the smiley a dunce: (:>
I disapprove of emoticons
Other