Re: GOTO considered (a necessary) evil?
by Abigail-II (Bishop) on Jul 15, 2002 at 14:45 UTC
|
Well, if I had to remove the goto, I would rewrite it as:
{
eval {
tie %session, 'Apache::Session::MySQL', $session, {
Handle => HH::DB->db_Main, LockHandle => HH::DB->db_Main
}
};
if ($@) {
if ($@ =~ /^Object does not exist/) {
$session = undef;
redo;
} else {
print $cgi->header;
die_nice('Database Error', 'Unable to connect at this time
+');
}
}
}
But a redo (just like next and last
is just a glorified goto. People who just balk at any sight
of a goto have at best heard about Dijkstra's article
Go To Considered Harmful (which wasn't titles bij Dijkstra, but
by Hoare), but never read the paper, or not understood it. Dijkstra just
warns that goto can easily lead to unstructured programs,
he doesn't say it's evil all the time.
Knuth has also written about this subject, in his Structured Programming
with the Go To statement. His view is less far away from Dijkstra as
that the titles suggest.
Abigail
| [reply] [d/l] [select] |
|
perl -le 'BAR: print 1; BAZ: for (2..3) {print; redo BAR; }'
This typo causes an infinite loop...
perl -le 'BAR: print 1; BAZ: for (2..3) {print; goto BAR; }'
(Updated to be less pedantic... the point is, goto
is for arbitrary jumping, redo is for controlled jumping to
the begining of a loop. Could you live w/o redo if you had
goto? yes. Does that mean you should just use goto and
not bother with redo? no.) | [reply] [d/l] [select] |
|
sub bar {
no warnings 'exiting';
redo FOO;
}
FOO: {
print "Hey!";
bar();
}
The redo worked and the label did not exist in a surrounding loop block. | [reply] [d/l] |
|
perl -le 'BAR: print 1; BAZ: for (2..3) {print; redo BAZ; }'
and
perl -le 'BAR: print 1; BAZ: for (2..3) {print; goto BAZ; }'
behave identically - looping infinitely.
Abigail
| [reply] [d/l] [select] |
Re: GOTO considered (a necessary) evil?
by VSarkiss (Monsignor) on Jul 15, 2002 at 15:29 UTC
|
As Abigail-II correctly points out above, the point of Dijkstra's paper was that programs should be easy to read and follow. At the time the paper was published, many programs were in Fortran and COBOL which did not provide "block-structure" facilities that we're used to today. Rather, code was re-used by setting flag variables and calling various flavors of GOTO.
Let me give a real-life example that I vaguely remember from <mumble> years ago. In Fortran-IV, if you had a piece of code that was used several times (say, calculating a pair of numbers), often you would not structure it as a subroutine, but would arrange for goto's around it. There are probably several reasons for this: in some cases it was (microscopically) faster, and a culture of "the way you do it". So off somewhere in your code you would have:
C common calculation code
C Fortran comments have a C in column 1
1100 if (argin(0) .eq. 0) j=1
....
C the equivalent of a "return"
goto N
(By the way, Fortran-IV labels were numeric.) You would then call this code in several places with:
C do the common calculation
assign 5500 to N
goto 1100
5500 continue
For those who haven't had the joy of reading stuff like this, an "assigned goto" allowed you to put the label that you want to execute next (in this case, 5500, the statement following the "goto 1100") into a variable, and jump there. That's how you effected a call and return without actually using CALL.
Now imagine "passing an argument" when you're doing this. There's no automatic save and restore, so you have to do that yourself. And if you wanted the calculation to do something slightly differently in one case, you would introduce a global variable, which you would set and use in two different places. Nest this a couple of levels deep, and you have very hard to debug code. Stuff like this was where the term "spaghetti code" originated, I think.
Dijkstra's point was to advocate not writing code like the above, but to use the less-popular call/return mechanisms. The title of the paper was meant to grab people's attention. (I didn't realize the title was Hoare's until I read Abigail's note.) The effect would probably be similar to some well-known computer scientist publishing "While loops considered harmful" today; it would make you sit up and take notice. Unfortunately, many people grabbed on to the title, but missed the main point.
All this, of course, is a roundabout way of saying: write clear and easy-to-understand code, goto or no goto. There's nothing wrong with using a goto (or in Perl, its kin: next, last, redo) as long as it don't obscure how the code works. | [reply] [d/l] [select] |
(tye)Re: GOTO considered (a necessary) evil?
by tye (Sage) on Jul 15, 2002 at 15:43 UTC
|
My favorite way to refactor loops that have the conditional in the middle is to use a subroutine because return in the middle of a subroutine seems an easy thing to understand (and to notice) when you come back to the code. It also avoids arguments with people who can't handle goto.
I also prefer to force eval to return a true value when it succeeds rather than checking $@ since there are cases where $@ can give the wrong impression about whether the eval was successful.
sub tieSession
{
while( 1 ) {
if( eval {
tie %session, 'Apache::Session::MySQL', $session, {
Handle => HH::DB->db_Main,
LockHandle => HH::DB->db_Main
};
1;
}
) {
return;
}
if( $@ !~ /^Object does not exist/ ) {
print $cgi->header;
die_nice( 'Database Error',
'Unable to connect at this time' );
}
undef $session;
}
}
So I don't consider goto inherently evil. I prefer your original code over your coworkers in at least some respects. I really hate the use of Perl bare blocks as loops and think it often leads to more spagetti code than even goto does (expecting people to notice a "redo" burried so deep inside in order to realize that a loop was suddenly created out of a bare block).
But I wouldn't over golf for "excellence". Is the code working? There is probably something more important to be working on. (:
- tye (but my friends call me "Tye") | [reply] [d/l] |
|
It also avoids arguments with people who can't handle goto.
I'd agree with you, except I ran into at least one developer who thought that returns from the middle of subroutines were just as unreasonable as goto's. :)
I'm in the "if I can understand what it's doing, it's fine" camp, myself. The goto in the original message was pretty clear, as is your example.
--
Mike
| [reply] |
|
| [reply] |
|
|
|
there are cases where $@ can give the wrong impression about whether the eval was successful.
Can you give an example of that?
| [reply] |
|
sub DESTROY { eval "1" }
eval 'my $x = bless {}; die "ouch\n"';
print "($@)\n";
which prints "()" not "(ouch\n)".
- tye (but my friends call me "Tye") | [reply] [d/l] |
Re: GOTO considered (a necessary) evil?
by atcroft (Abbot) on Jul 15, 2002 at 14:41 UTC
|
I know of at least one general discussion on using GOTO (Would you use 'goto' here?), although I would guess there are likely more buried around here somewhere.
I can see your use for it, but would be concerned that the way you coded it could perhaps cause an endless loop (although I will assume there is additional code that was excluded from the example to prevent this). To me, though, both are about equally as readable.
Just my opinion, though, and I look forward to seeing the responses of others regarding the issue.
Update: Actually, looking at both solutions, both tend to suggest that a continuous loop might be possible (or am I reading those wrong?).
| [reply] |
Re: GOTO considered (a necessary) evil?
by FoxtrotUniform (Prior) on Jul 15, 2002 at 15:08 UTC
|
In this case, I'm not particularly inclined to complain
about the goto, though I find an explicit loop
a bit easier to read (in that the branching structure's
fairly well-defined; when I see a label, I look through all
the applicable code for gotos, even if I'm
fairly sure that there won't be more than the obvious one).
In my experience, the "goto EVIL!" meme is
propagated either by well-meaning but naive instructors who
don't want to "confuse" beginning programmers with the
vagaries of when gotos are appropriate, but
don't want their students picking up bad habits, or by
cargo-cult instructors who were taught that
goto is uniformly bad, didn't bother to
question the statement, and go on to teach others. Either
way, it's irritating, but probably a net win.
--
The hell with paco, vote for Erudil!
:wq
| [reply] [d/l] [select] |
Re: GOTO considered (a necessary) evil?
by ferrency (Deacon) on Jul 15, 2002 at 15:55 UTC
|
There are some benefits to using next or redo or a while or for loop instead of goto. One of those is, the perl compiler has more information about the structure of your code and its control flow, when you use something other than goto. I'm not going to make any uninformed assertions about the effects this has on optimization. Instead I'll bring up some more practical concerns.
If your target label in a goto is undefined, perl won't complain until it tries to actually execute the goto, even when using strict and warnings. If your goto is handling a "once in a thousand years" case, then you're likely not to notice this typo until it's too late. The same thing happens when a label gets deleted or changed inadvertantly. A case where the same label is used twice can cause other confusion, and I haven't seen use strict or warnings catch that case either.
If you are going to go through the trouble of making your code use strict, it's probably a good idea not to use code which subverts the strictness unnecessarily.
This is not to say "don't use goto," even though I tend not to like it. Just be aware of the potential consequences.
Finally, from perldoc -f goto:
The goto-LABEL form finds the statement labeled with LABEL and resumes
execution there ...
The author of Perl has never felt the
need to use this form of goto (in Perl, that is--C is another matter).
Update:Abigail is right: labels on non-goto's have the same problem. I use labels on next when necessary, and much more frequently than I use goto. But I try not to use labels when they are not necessary, for the reasons I outlined above.
Alan | [reply] [d/l] [select] |
|
last, next and redo
can take a label as well. And then you will have the same
problems if you now point out with goto.
Yet, next and friends having an optional label
is seen as a feature, not a misfeature. It might very well
be that the author of Perl had used the goto LABEL
if he had not added optional labels to next,
last and redo.
Abigail
| [reply] [d/l] [select] |
|
while (1) {
....
....
last unless (EXPR);
}
Which makes very clear that this is a loop (even though it might not loop more than once 99% of the time) and it "forces" some structure (which is not always a bad thing), and it might make you see the problem from a new perspective - TIMTOWDI after all.
--
Joost downtime n. The period during which a system
is error-free and immune from user input.
| [reply] [d/l] [select] |
Re: GOTO considered (a necessary) evil?
by John M. Dlugosz (Monsignor) on Jul 15, 2002 at 16:22 UTC
|
In well-defined cases, such as jumping to the beginning or end of a loop, we have special keywords that mean this. It is not as bad as goto because you know what they mean in terms of structure, and we also have idioms that go with them.
"Go back to the beginning" is a well-defined point, not a random jump into the middle of the logic.
Check out the redo keyword. I've used it in cases like this. | [reply] [d/l] |
Re: GOTO considered (a necessary) evil?
by particle (Vicar) on Jul 15, 2002 at 15:26 UTC
|
after reading this thread and re-reading Would you use 'goto' here?, i'm beginning to think there should be optional warnings for goto usage. perhaps use warnings 'goto'; could warn on goto LABEL and goto EXPR, but pass goto &NAME.
of course, this shouldn't be implemented without an agreement from the perl community that goto in the traditional sense should someday be deprecated.
thoughts?
~Particle *accelerates*
| [reply] [d/l] [select] |
|
i'm beginning to think there should be optional warnings for goto
usage. perhaps use warnings 'goto'; could warn on goto LABEL and goto
EXPR, but pass goto &NAME.
I think that is a very bad idea. Warnings are there to prevent programmers
from making accidental mistakes. Warnings are done if
variables have unexpected values (comparing integers with ==,
adding undefined values, dereferencing non-references), when you try
to do something that cannot be done (open a bi-directional pipe), use a
deprecated feature (implicite @_), or did something you probably didn't
want to do (exiting eval with next, mying the same
variable twice in the same context</code>), etc, etc.
But the use of goto is not deprecated, and you will not get
much support to get it deprecated. And it's hardly likely someone types
goto by accident.
Warning should be used to prevent programmers from making mistakes -
as soon as warnings will be misused to force a coding style upon
programmers, use of use warnings and -w
will plummit - and rightly so. Forcing a coding style, one way or the
other, upon something else is Pythonesque.
Abigail
| [reply] [d/l] [select] |
|
| [reply] |
|
(Ten years from now, at the meeting of the Perl Programming Style Cabal...)
"I want to remove regexes from the language. Lots of people uglify their programs by using it."
"All in favor of removing regexes, say aye. All opposed, say nay."
(A chorous of "Aye"s fills the room.)
=cut
--Brent Dax
There is no sig.
| [reply] |
|
| [reply] |
Re: GOTO considered (a necessary) evil?
by sedhed (Scribe) on Jul 16, 2002 at 19:20 UTC
|
Without getting into the goto issue, may I offer the code I use for tieing a session using Apache::Session::*. It is not a loop at all, therefore no chance of an infinite loop. It makes two tries at a session, once using the supplied ID (if any), and if that fails it tries a second time using undef, to get a new session. Failing that, it dies.
# $id is either a cookie-passed session ID or undef
# $sargs is a hashref of options
eval { tie %session, 'Apache::Session::Postgres', $id, $sargs };
if ($@ =~ /^Object does not exist/) { # try to get a new session
eval { tie %session, 'Apache::Session::Postgres', undef, $sargs };
die "Can't get new session: $@" if $@;
} elsif ($@) {
die "Can't get session. ID (if any): '$id' : $@";
}
cheers! | [reply] [d/l] |
Re: GOTO considered (a necessary) evil?
by BrentDax (Hermit) on Jul 17, 2002 at 00:50 UTC
|
| [reply] [d/l] |