Re: To Kill a Meme: while(defined($line = <>))
by theorbtwo (Prior) on Nov 03, 2003 at 06:53 UTC
|
One minor nit: You missed a way to get a false-but-defined value. It's possible if you've set $/=\1, that is, if you're reading a byte at a time.
BTW, while you're right that it's rarely important to have it there, it certianly doesn't hurt, and there's a school of thought that it's almost always better to be explicit then implicit.
(In case you were confused, this is an agreement, with caveats.)
Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).
| [reply] [d/l] |
|
|
One minor nit: You missed a way to get a false-but-defined value. It's possible if you've set $/=\1, that is, if you're reading a byte at a time.
One minor nit: that won't work, I quote perldoc perlop
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:
You can test if you need convincing ;)
E:\>perl
$|=1;
$/=\1;
print "[$_]" while <>;
__END__
abcd
[a][b][c][d][
]0000000000000
[0][0][0][0][0][0][0][0][0][0][0][0][0][
]^Z
update:
theorbtwo: that was my point, defined is implicit, so it wouldn't matter if it was false
sauoq: I was not responding to the entire meditation, but to theorbtwos response.
I do not consider using while(defined($_=<>)) a meme.
| MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!" | | I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README). | | ** The third rule of perl club is a statement of fact: pod is sexy. |
| [reply] [d/l] [select] |
|
|
I think you missed his point, if not the point of the whole meditation. The behavior you cite from the docs did not exist in 5.004_04. The fact that it didn't could result in some obscure bugs. I pointed out two ways you could run into trouble because of it. And theorbtwo was trying to point out another one. (He was wrong, but only because setting $/ to a reference to a number in order to read fixed length records was not supported in 5.004_04.)
You can test if you need convincing and you have perl 5.004_04 ;-)
$ perl5.00404 -e '$/=\1; print "[$_]" while <>;'
abcd
0000
^D
[abcd
0000
]$
And if you need some evidence that the documentation you pasted is irrelevant to the case at hand:
$ perl5.00404 -we'$/="0"; print $l while ($l = <>)'
Value of <HANDLE> construct can be "0"; test with defined() at -e line
+ 1.
foo000bar
foo0$
-sauoq
"My two cents aren't worth a dime.";
| [reply] [d/l] [select] |
|
|
$|++;
$/=\1;
print "[$_]" while ($_=<>, $_)
__END___
abcd
[a][b][c][d][
]0000000000000
(I see no holes with sauoq's response, though.)
Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).
| [reply] [d/l] [select] |
|
|
One minor nit: You missed a way to get a false-but-defined value. It's possible if you've set $/=\1, that is, if you're reading a byte at a time.
Actually... and I'm glad you brought this up because I meant to comment on it...
No. Not in 5.004_04. That feature was introduced sometime in 5.005, so the definedness bug could never have been activated by it.
-sauoq
"My two cents aren't worth a dime.";
| [reply] |
Re: To Kill a Meme: while(defined($line = <>))
by Zaxo (Archbishop) on Nov 03, 2003 at 03:22 UTC
|
Agreed, that warning was probably a mistake. Nonetheless, code written for portability ought to either keep that form, or use 5.004_05;. Too bad that was too early for no warnings 'zero'; (or whatever the warning tag might have been)
| [reply] [d/l] [select] |
Re: To Kill a Meme: while(defined($line = <>))
by Juerd (Abbot) on Nov 03, 2003 at 08:03 UTC
|
Whenever you use while (my $line = readline $fh), perl always adds defined if you haven't done so already. I think that this inconsistency between code and the ops that are actually executed is worse and causes people unfamiliar with Perl to think the program will not give that last blank or 0 line.
I am used to writing while (defined(my $line = readline $fh)) and will continue to write it like this. It does not cause any bug, what it does is crystal clear and the 9 extra characters won't hurt anyone.
Whenever I see the defined thing missing, I add it for clarity.
I read your post a couple of times, but the only argument I see for getting rid of "defined" is that it is not necessary. I'd understand your plea if defined would cause strange bugs, but it doesn't. It usually prevents them. Do you think we should also forget all about whitespace as well, just because it is not necessary?
And here we are. Years later and defined has been typed much more often in conditionals to avoid warnings than together with while. Those warnings ("Use of uninitialized value") are there for a reason. The very same reason that testing for definedness is usually a GOOD idea. It usually takes less than a second to type, and saves a lot of time when debugging. Perl's adding defined automatically to while is for me not a reason to not use it.
| [reply] [d/l] [select] |
|
|
It usually prevents them.
Usually, it doesn't do anything.
Even in the cases where the while doesn't check for definedness, like when you add something to the loop condition, it still usually doesn't do anything.
In order for it to do anything at all, you have to be either A) using a perl <= 5.00404 or B) doing something more complex in your while loop than a simple assignment from a filehandle read and one of the following must be true: 1) you are reading fixed length one character records and you retrieve a record containing a single '0', 2) you have set $/ to a string containing one '0', or 3) the last line of a file you are reading must contain a single '0' and not be terminated with $/.
If you need to code defensively for those conditions, go right ahead. Most people don't most of the time.
Besides, you seem to have a good understanding of why you add it. Many don't. Many people write it that way because they have the vague notion that they need to for some reason. They don't add it for clarity.
I, for one, think it does very little to add clarity. I think that seeing code with an explicit defined() like that has caused people unfamiliar with Perl to think the program will not give that last blank or 0 line when the explicit defined() is missing. This is confusing because, in %99.99 of the cases, the definedness check doesn't matter at all regardless of whether it is implicit or explicit. The program would go merrily on its way if the check didn't even exist.
As theorbtwo said in another post, some people are of the mind that being explicit is always better. I do understand that train of thought even if I've rarely taken it to the extreme of spelling out r-e-a-d-l-i-n-e. There are some benefits to being explicit but I think that being explicit all of the time just for the sake of — well, for the sake of being explicit — misses the point.
One of my favorite things about Perl is that I don't have to be explicit. That's a welcome relief from the languages I started out with.
It's great to be able to think about the parts of a problem that interest me and to let perl take care of the parts that don't. Sure, I've got to know enough about Perl to fix things when problems arise. And I do. But, in practice, relatively few problems have come up as a result of perl not handling its parts intuitively. With Perl, a much higher proportion of my debugging time is spent on higher level problems than with languages where being explicit is a requirement, not an option.
With Perl's expressive power, code can be focused tightly on the problem and elegant and succinct solutions are normal. I don't see any reason to dilute code by being explicit about such minor things as definedness checks when it just isn't necessary.
Edit: The anonymonk post below is absolutely correct, and I have no excuse other than fatigue. I've edited the text above for correctness.
-sauoq
"My two cents aren't worth a dime.";
| [reply] |
|
|
Usually, it doesn't do anything. (...) In order for it to do anything at all, you have to be either A) using a perl <= 5.00404 or B) doing something more complex in your while loop than a simple assignment from a filehandle read and one of the following must be true: 1) you are reading fixed length records and retrieve a record containing all '0's, 2) you have set $/ to a string of one or more '0's, or 3) the last line of a file you are reading must contain a string of one or more '0's and not be terminated with $/.
So by routinely adding 9 characters that are easy to remember, I no longer have to remember these 6 permutations that I will probably forget again within the next hour.
Just like how by using strict, I don't have to remember that undeclared variables are implicitly global.
I do not mind typing a little more if that means that I can forget a lot and get away with it.
Especially since the extra code cannot introduce a bug, but only prevent obscure ones, please let me and the rest of the world type "defined". Perl thinks it is needed too: it adds the test in case you forget it. That's how important perl thinks it is, and I agree with perl. I agree strongly enough to explicitly use that "defined".
I wish everyone continues to use defined. I hope that tutorials and books will continue to preach it, even when it isn't necessary. This is just like "use strict;" in many ways: the extra keystrokes prevent bad things.
I sincerely hope that not too many beginners read your post, and that people who already know Perl well are sane enough to evaluate and then disregard it.
How do you feel about the "return" statement as the last statement in a sub? I like it and use it whenever I can (i.e. when the sub is not an lvalue-sub), even though Perl implicitly returns the last evaluated expression anyway.
| [reply] |
|
|
| [reply] |
Re: To Kill a Meme: while(defined($line = <>))
by Abigail-II (Bishop) on Nov 03, 2003 at 09:47 UTC
|
Unless you are still supporting old versions of perl, please, try to lay this old habit to rest.
Your post gives the impression that it's somehow wrong to
be explicit, because Perl already does so automatically.
What's next, a plea to not use length ($_),
because Perl will fill in the $_? A plea to not close a
filehandle because Perl will close it for you? A plea to
not use write an explicit return if the last
line of a sub is return EXPR;?
I'm all for actively discouraging styles or idioms that are
wrong, that easily lead to mistakes, or that are misleading.
But your posts don't give more reasons than "it was needed
way back then, but it no longer is". But just because it's
no longer needed, it's not wrong, doesn't easily lead to
mistakes (quite the opposite) nor is it misleading.
Abigail
| [reply] [d/l] [select] |
|
|
Your post gives the impression that it's somehow wrong to be explicit,
That's certainly not what I hoped to convey.
As I said in a reply to Juerd, I relish the fact that I don't have to be explicit with everything, but that's a very different sentiment and I was addressing a very different point.
What I don't like about the whole while-defined-readline business is that most people use it without a clue why they are using it.
Maybe I should have chosen a less violent title. And perhaps, instead of ending the node with "please, try to lay this old habit to rest" I should have said, "if you don't know why you are doing it, don't bother." I really don't care half as much as some seem to think I do now. :-)
But just because it's no longer needed, it's not wrong, doesn't easily lead to mistakes (quite the opposite) nor is it misleading.
I mostly agree with that except that I think it does lead to mistakes. Not coding mistakes, but conceptual mistakes. When it is coded explicitly, it seems to indicate to perl beginners that it is necessary for a common case. Then they start imagining what that common case is and they get it all wrong but they don't know that. Then those assumptions bleed into other code they write.
-sauoq
"My two cents aren't worth a dime.";
| [reply] |
|
|
I mostly agree with that except that I think it does lead to mistakes. Not coding mistakes, but conceptual mistakes. When it is coded explicitly, it seems to indicate that it is necessary for a common case.
Well, generally, the defined test is
necessary. The "common" case is the exception where Perl
is providing the short-cut. If there is any danger, it's
that people get used to writing while ($line = <>), and think that they can also
write: while ($cond and $line = <>) or
$line = <>; while ($line) {.... ; $line = <>}.
Now, I don't think the danger is anything to worry about, but
I've seen cases where the defined() test was missing where it
should have been.
Now, I'd be really interested in hearing what you think is
the common case, and where people get it wrong by using
defined ($line = <>).
Abigail
| [reply] [d/l] [select] |
|
|
|
|
|
|
|
|
|
|
A plea to not close a filehandle because Perl will close it for you?
Actually, this is one thing I always advise people to do - use lexical filehandles in tight scopes, and let their scoping take care of closing. That's much cleaner and easier to maintain than package filehandles.
It's related to the distinction between in control flow GOTO-driven and structured programs: you don't have to figure out the temporal sequence of code to understand where a filehandle comes into play and when its lifecycle ends, all you need is to look at the spatial layout of the source.
Makeshifts last the longest.
| [reply] |
|
|
Isn't it at least theoretically possible for close to return an error? I'm not sure what, if anything could be done to rectify it if it did, but it could be used to alter the course of the rest of the program, even if it was only to log an error and exit.
Is there any way of trapping and handling such an error if you allow an unclosed lexical filehandle to just go out of scope?
I guess if you where using IO::*, you could subclass the DESTROY method, but would the filehandle still be open at that point? Or would an error code be accessible?
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail
Hooray!
Wanted!
| [reply] |
|
|
|
|
|
|
|
I think this (letting perl close file automatically) is a bad idea.
It does happen on NFS that close returns an error (when net connection breaks or quota is exceeded). (It can also happen if the disk is full or physically bad.) But Perl only gives a severe warning in this case, not an error, so if you don't see the warning (because cgi script or
scrolled out of screen by make's messages), it will seem that it's run normally.
| [reply] |
|
|
|
|
|
|
Re: To Kill a Meme: while(defined($line = <>))
by pg (Canon) on Nov 03, 2003 at 04:33 UTC
|
I agree with sauoq.
Just want to add a little bit for people new to Perl, so that they are less confused. In general, to use and not to use "defined" are not logically equivalent, as Perl evulates both undef and empty string to false, but with defined, it only evaluates undef to false: (but in the particular case of assignment from <> to scalar, see sauoq's original post for explanation)
Try this code by uncommenting one of those two while lines, and observe the result:
use strict;
use warnings;
my $str = "";
#while (defined($str)) {#caution: this is different from what sauoq ha
+d, as this is not an assignment from <>
#while ($str) {
print "inside while loop\n";
}
| [reply] [d/l] |
|
|
But don't forget (which is the point of sauoq's rant) that Perl automatically checks defined when you're assigning from a filehandle to a scalar in a while loop condition.
$ perl -MO=Deparse -e'while($line=<>){}'
while (defined($line = <ARGV>)) {
;
}
-e syntax OK
Makeshifts last the longest.
| [reply] [d/l] |
|
|
Update:
You missed the real point. This has nothing to do with whether Perl "automatically" checks undef. The real point here is that, under a normal situation without set $/, you don't get a real empty string or a "0" back, so those posibilities are eliminated, and this leaves undef the only condition that may evaluate $line to false, thus the use of "defined" is not neccessary here.
A placehold for original:
I realized the confusion I had in the original reply, and removed it. Then I saw sauoq had already replied.
It would be okay if there was no reply, but it is immoral to make his reply funny ;-), especailly when he is right. So I leave this comment here to confirm what he said is true, and that was my confusion in my original post.
| [reply] |
|
|
|
|
Re: To Kill a Meme: while(defined($line = <>))
by liz (Monsignor) on Nov 03, 2003 at 08:46 UTC
|
Note that there are still plenty of places where it makes sense to use defined inside a while loop. This is specifically a plea to avoid it in cases where you are reading from a filehandle like this: while( defined( $line = <FH> ) ) and nothing more.
I may be blunt in this regard, but if there is a meme that should be killed in any non-oneliner programs, it's the absence of using defined() while reading from a file handle. It just adds too much extra processing when trying to read source code, especially when you have experience in other programming languages. This property of while is different from other conditional constructs, and it's even different from itself when not readng from a file handle (as you yourself point out).
This is completely seperate from any warnings that Perl may have had in the past. This is about maintainability of Perl source code.
As Juerd and others already pointed out: there is no harm in using defined() in these cases. And the extra characters typed easily offset any time lost when someone tries to read the source code later.
To me, the request to please stop using defined() when reading from a file handle, is almost the same as a request to please stop documenting your programs. It's penny wise, but pound foolish.
Liz | [reply] |
Re: To Kill a Meme: while(defined($line = <>))
by Nkuvu (Priest) on Nov 03, 2003 at 04:28 UTC
|
Huh. I've never seen that line. I guess it means that I'm a relative Perl newbie, huh? (The first version of Perl that I seriously used was 5.6, though there was some very minor dabbling with Perl 4-something)
All of my file readings that use while loops pretty much use the syntax while(chomp($line = <FH>)) already...
| [reply] [d/l] |
|
|
while(chomp($line = <FH>))
This is probably a more dangerous meme than while($line = <>) ever was—if your file is missing a terminal linefeed (or CRLF, as the case may be) you'll skip the last line. Not a common failing of text files, but all you need is one for it to bite you, hard.
If God had meant us to fly, he would *never* have given us the railroads. --Michael Flanders
| [reply] [d/l] [select] |
|
|
Huh. Learn something new every day. Thanks for the heads up.
| [reply] |
|
|
All of my file readings that use while loops pretty much use the syntax while(chomp($line = <FH>) already...
You aren't by any chance the author of the Perl books that are
in use by HP-Education, are you? For a long time I thought
that the Perl books SUN-Education made were the worst Perl books ever made, but then I got to see the HP books, full of
gems like while(chomp($line = <FH>).
Abigail
| [reply] [d/l] [select] |
|
|
Nope, no authorship here. Especially not for anything on Perl.
And while I can't say that I am really happy to have provided an example of a "gem" that you think is the worst Perl ever, I do appreciate knowing that this isn't the prescribed way to do things. I've never had this bite me, but it's good to know that it has big teeth.
| [reply] |