"Good Programming" Replacement for exit statement [duplicate] - loops

This question already has answers here:
Is it a bad practice to use break in a for loop? [closed]
(19 answers)
Closed 5 years ago.
I have a fairly simple structure:
do i = 1,x
if (condition) then
do_stuff
exit
end if
end do
If the do-loop gets big enough, the exit statement wouldn't be good anymore (I look at it approx. like I look at go to statements).
I'm looking for a cleaner way to exit the loop when appropriate so that it is also more clear what is happening for somebody else looking over my code.
One thing I thought of that might clean up would be something along the lines of
lkeepgoing = .true.
iterator = 1
while (lkeepgoing) then
if (condition) then
do_stuff
lkeepgoing = .false.
end if
iterator = iterator+1
end while
While I think it clears up why I want to exit the loop without having to look through the whole loop, it looks overly complicated I think.
So the question: How do you exit do-loops when a condition is met in a clear, clean way that doesn't use spaghetti-code-prone statements?

There's nothing wrong with the way your first code snippet uses exit. A little jump such as that is hardly spaghetti code. And compared with your second snippet it's considerably clearer that you are making a disciplined early exit from a loop when a certain condition is met.
Bear in mind that exit is very confined in where it can jump to, while go to can be used to jump all over the place.
Don't adhere to one-size-fits-none rules such as never use goto too strictly, certainly not when they make code worse.

Related

What does an "extra" semicolon means? [duplicate]

This question already has answers here:
Two semicolons inside a for-loop parentheses
(4 answers)
Endless loop in C/C++ [closed]
(12 answers)
Closed 4 years ago.
I was searching for an explanation for the "double semicolon" in the code:
for(;;){}
Original question.
I do not have enough reputation to even leave a comment so I need to create a new question.
My question is,
What does an "extra" semicolon means. Is this "double semicolon" or "extra semicolon" used for "something else"?
The question comes from a person with no knowledge of programing, just powered on my first arduino kit and feel like a child when LED blinked.
But it is the reality that the questions, like general occurence, are radiating the actual knowledge of the person asking the question.
And beyond "personal preference" in using while(1) or for(;;) is it helpful in using for(;;) where you do not have enough room for the code itself?
I have updated the question.
Thank you for the quick explanation. You opened my eyes with the idea of not using anything in for loop = ). From basic high school knowledge I am aware of for loop so thank you for that.
So for(;;) returns TRUE "by default"?
And my last line about the size of the code?
Or it is compiled and using for or while actually does not affect the compiled code size?
A for loop is often written
int i;
for (i = 0; i < 6; i++) {
...
}
Before the first semicolon, there is code that is run once, before the loop starts. By omitting this, you just have nothing happen before the loop starts.
Between the semicolons, there is the condition that is checked after every loop, and the for loop end if this evaluates to false. By omitting this, you have no check, and it always continues.
After the second semicolon is code that is run after every cycle, before that condition is evaluated. Omitting this just runs additional code at that time.
The semicolons are always there, there is nothing special about the face that they are adjacent. You could replace that with
for ( ; ; )
and have the same effect.
While for (;;) itself does not return true (It doesn't return anything), the second field in the parentheses of the for always causes the loop to continue if it is empty. There's no reason for this other than that someone thought it would be convenient. See https://stackoverflow.com/a/13147054/5567382. It states that an empty condition is always replaced by a non-zero constant, which is the case where the loop continues.
As for size and efficiency, it may vary depending on the compiler, but I don't see any reason that one would be more efficient than the other, though it's really up to the compiler. It could be that a compiler would allow the program to evaluate as non-zero a constant in the condition of a while loop, but recognise an empty for loop condition and skip comparison, though I would expect the compiler to optimize the while loop better. (A long way of saying that I don't know, but it depends on a lot.)

Why do some kernel programmers use goto instead of simple while loops?

When I learned C, teacher told me all day long: "Don't use goto, that's a bad habit, it's ugly, it's dangerous!" and so on.
Why then, do some kernel programmers use goto, for example in this function, where it could be replaced with a simple
while(condition) {}
or
do {} while(condition);
I can't understand that. Is it better in some cases to use goto instead of while/do-while? And if so, why?
Historical context: We should remember that Dijkstra wrote Goto Considered Harmful in 1968, when a lot of programmers used goto as a replacement for structured programming (if, while, for, etc.).
It's 44 years later, and it's rare to find this use of goto in the wild. Structured programming has already won, long ago.
Case analysis:
The example code looks like this:
SETUP...
again:
COMPUTE SOME VALUES...
if (cmpxchg64(ptr, old_val, val) != old_val)
goto again;
The structured version looks like this:
SETUP...
do {
COMPUTE SOME VALUES...
} while (cmpxchg64(ptr, old_val, val) != old_val);
When I look at the structured version, I immediately think, "it's a loop". When I look at the goto version, I think of it as a straight line with a "try again" case at the end.
The goto version has both SETUP and COMPUTE SOME VALUES on the same column, which emphasizes that most of the time, control flow passes through both. The structured version puts SETUP and COMPUTE SOME VALUES on different columns, which emphasizes that control may pass through them differently.
The question here is what kind of emphasis do you want to put in the code? You can compare this with goto for error handling:
Structured version:
if (do_something() != ERR) {
if (do_something2() != ERR) {
if (do_something3() != ERR) {
if (do_something4() != ERR) {
...
Goto version:
if (do_something() == ERR) // Straight line
goto error; // |
if (do_something2() == ERR) // |
goto error; // |
if (do_something3() == ERR) // |
goto error; // V
if (do_something4() == ERR) // emphasizes normal control flow
goto error;
The code generated is basically the same, so we can think of it as a typographical concern, like indentation.
In the case of this example, I suspect it was about retrofitting SMP support into code that was originally written in a non-SMP-safe way. Adding a goto again; path is a lot simpler and less invasive than restructuring the function.
I can't say I like this style much, but I also think it's misguided to avoid goto for ideological reasons. One special case of goto usage (different from this example) is where goto is only used to move forward in a function, never backwards. This class of usages never results in loop constructs arising out of goto, and it's almost always the simplest, clearest way to implement the needed behavior (which is usually cleaning up and returning on error).
Very good question, and I think only the author(s) can provide a definitive answer. I'll add my bit of speculation by saying that it could have started with using it for error handling, as explained by #Izkata and the gates were then open to using it for basic loops as well.
The error handling usage is a legitimate one in systems programming, in my opinion. A function gradually allocates memory as it progresses, and if an error is encountered, it will goto the appropriate label to free the resources in reverse order from that point.
So, if the error occurs after the first allocation it will jump to the last error label, to free only one resource. Likewise, if the error occurs after the last allocation, it will jump to the first error label and run from there, freeing all the resources until the end of the function. Such pattern for error handling still needs to be used carefully, especially when modifying code, valgrind and unit tests are highly recommended. But it is arguably more readable and maintainable than the alternative approaches.
One golden rule of using goto is to avoid the so-called spaghetti code. Try drawing lines between each goto statement and its respective label. If you have lines crossing, well, you've crossed a line :). Such usage of goto is very hard to read and a common source of hard to track bugs, as they would be found in languages like BASIC that relied on it for flow control.
If you do just one simple loop you won't get crossing lines, so it's still readable and maintainable, becoming largely a matter of style. That said, since they can just as easily be done with the language provided loop keywords, as you've indicated in your question, my recommendation would still be to avoid using goto for loops, simply because the for, do/while or while constructs are more elegant by design.

what is one entry and one exit of a simple construct?

I am reading some C text at the address https://cs.senecac.on.ca/~btp100/pages/content/const.html.
In the section "STRUCTURED PROGRAMMING", the author mentioned: "Structured programs are understandable, testable and readily modifiable. They consist of simple constructs, each of which has one entry point and one exit point."
I understood what is a structured program, but I am not really understanding the idea "one entry point and one exit point". What if we do not have such stuff?
Can anyone elaborate on that, please?
Look at the Flags example close to the bottom and Avoiding Jumps below that: https://cs.senecac.on.ca/~btp100/pages/content/const.html#fla
What they're basically trying to say here is that you could have some sort of loop (for/while/whatever) where you could use something like break to exit a loop prematurely, rather than waiting on the actual condition that you're checking in the loop to become false and have the loop exit normally. In this case you would have two exit points.
They suggest the use of a flag variable added to the loop's condition to have a single exit point, makes sense.
The use of continue is another example where you can "break structure." You could use continue to stop the current iteration of the loop and reenter it, where in this case you would have multiple entry points.
Things like that can make code a lot harder to read and be able to follow the flow, even though sometimes it may seem necessary to do so.

Do Perl loop labels count as a GOTO?

Generally, it is good practice to avoid GOTOs. Keeping that in mind I've been having a debate with a coworker over this topic.
Consider the following code:
Line:
while( <> ) {
next Line if (insert logic);
}
Does using a loop label count as a goto?
Here is what perlsyn in perldoc has to say:
Here's how a C programmer might code up a particular algorithm in Perl:
for (my $i = 0; $i < #ary1; $i++) {
for (my $j = 0; $j < #ary2; $j++) {
if ($ary1[$i] > $ary2[$j]) {
last; # can't go to outer :-(
}
$ary1[$i] += $ary2[$j];
}
# this is where that last takes me
}
Whereas here's how a Perl programmer more comfortable with the idiom might do it:
OUTER: for my $wid (#ary1) {
INNER: for my $jet (#ary2) {
next OUTER if $wid > $jet;
$wid += $jet;
}
}
My take on this is no because you are explicitly telling a loop to short circuit and advance however my coworker disagrees, says that it is just a fancy GOTO and should be avoided. I'm looking for either a compelling argument or documentation that explains why this is or is not a GOTO. I'll also accept an explanation for why this is or is not considered good practice in perl.
Dijkstras intent was never that anything resembling goto is to be considered harmful. It was that the structure of code where gotos are used as the main construct for almost any kind of program flow change will result in what we today call spaghetti code.
You should read the original article and keep in mind that it was written in 1968 when labeled jumps was the main flow control constructs in just about all programming languages.
https://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF
The danger of GOTO labels is that they create spaghetti code and make the logic unreadable. Neither of those will happen in this case. There is a lot of validity in using GOTO statements, much of the defense coming from Donald Knuth [article].
Delving into the differences between your C and Perl example... If you consider what is happening at the assembly level with your C programs, it all compiles down to GOTOs anyway. And if you've done any MIPS or other assembly programming, then you've seen that most of those languages don't have any looping constructs, only conditional and unconditional branches.
In the end it comes down to readability and understandability. Both of which are helped an enormous amount by being consistent. If your company has a style guide, follow that, otherwise following the perl style guide sounds like a good idea to me. That way when other perl developers join your team in the future, they'll be able to hit the ground running and be comfortable with your code base.
Who cares whether it counts as goto as long as it makes the code easier to understand? Using goto can often be MORE readable than having a bunch of extra tests in if() and loop conditions.
IMO, your code comparison is unfair. The goal is readable code.
To be fair, you should compare an idiomatic Perl nested loop with labels against one without them. The C style for and blocked if statement add noise that make it impossible to compare the approaches.
Labels:
OUTER: for my $wid (#ary1) {
INNER: for my $jet (#ary2) {
next OUTER if $wid > $jet;
$wid += $jet;
}
}
Without labels:
for my $wid (#ary1) {
for my $jet (#ary2) {
last if $wid > $jet;
$wid += $jet;
}
}
I prefer the labeled version because it is explicit about the effect of the condition $wid > $jet. Without labels you need to remember that last operates on the inner loop and that when the inner loop is done, we move to the next item in the outer loop. This isn't exactly rocket-science, but it is real, demonstrable, cognitive overhead. Used correctly, labels make the code more readable.
Update:
stocherilac asked what happens if you have code after the nested loop. It depends on whether you want to skip it based on the inner conditional or always execute it.
If you want to skip the code in the outer loop, the labeled code works as desired.
If you want to be sure it is executed every time, you can use a continue block.
OUTER: for my $wid (#ary1) {
INNER: for my $jet (#ary2) {
next OUTER if $wid > $jet;
$wid += $jet;
}
}
continue {
# This code will execute when next OUTER is called.
}
I think the distinction is somewhat fuzzy, but here's what the goto perldoc states about the (frowned upon) goto statement:
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). (The difference is that C does not offer named loops combined with loop control. Perl does, and this replaces most structured uses of goto in other languages.)
The perlsyn perldoc, however, says this:
The while statement executes the block as long as the expression is true. The until statement executes the block as long as the expression is false. The LABEL is optional, and if present, consists of an identifier followed by a colon. The LABEL identifies the loop for the loop control statements next, last, and redo. If the LABEL is omitted, the loop control statement refers to the innermost enclosing loop. This may include dynamically looking back your call-stack at run time to find the LABEL. Such desperate behavior triggers a warning if you use the use warnings pragma or the -w flag.
The desperate behaviour bit doesn't look too good to me, but I may be misinterpreting its meaning.
The Learning Perl book (5th edition, page 162) has this to say:
When you need to work with a loop block that's not the innermost one, use a label.
...
Notice that the label names the entire block; it's not marking a target point in the code. [This isn't goto after all.]
Does that help clear things up? Probably not... :-)
Labeled loop jumps in Perl are GOTOs as much as C's break and continue are.
I would answer it like this, and I'm not sure if this is sufficiently different from what others have said:
Because you can only only move inside of the current scope, or to a parent scope, they're much less dangerous than what is typically implied by goto, observe:
if (1) {
goto BAR;
die 'bar'
}
BAR:
This should work obviously, but this won't (can't move in this direction).
if (0) {
BAR:
die 'bar'
}
goto BAR;
Many use cases of labels differ from goto in that they're just more explicit variants of core flow control. To make a statement that they're categorically worse would be to imply that:
LOOP: while (1) {
next LOOP if /foo;
}
is somehow worse than
while (1) {
next if /foo/;
}
which is simply illogical if you exclude style. But, speaking of style, the latter variant is much easier to read - and it does stop you from having to look up for the properly named label. The reader knows more with next (that you're restarting the loop in the current scope), and that is better.
Let's look at another example
while (1) {
while (1) {
last;
}
stuff;
}
-vs-
FOO: while (1) {
BAR: while (1) {
next FOO;
}
stuff;
}
In the latter example here next FOO, skips stuff -- you might desire this, but it is bad idea. It implies that the programmer has read a parent scope to completion which is an assumption probably better avoided. In summary, label isn't as bad as goto and sometimes they can simplify code; but, in most cases they should be avoided. I usually rewrite loops without labels when I encounter them on CPAN.
gotos are bad because they create hard to understand code--particularly, what is often called "Spaghetti Code". What's hard to understand about next Line...??
You can call it a loop "name", and it really is something to help emphasize loop boundaries. You're not jumping into an arbitrary point in relation to the loop; you're going back to the top of a loop.
Sadly enough, if it is a group or house standard, there might be nothing to convince the group that it's not a goto. I had a manager who absolutely insisted that a ternary operator made things hard to read, and preferred I use if-blocks for everything. I had a pretty good argument anything can be done in the clauses of an if-else, but that a ternary made it explicit that you were looking for a particular value. No sale.
This kind of jump is a disciplined used of a goto-like statement. So it's certainly less harmful than undisciplined use of goto. (As kasperjj wrote, "Dijkstras intent was never that anything resembling goto is to be considered harmful.")
IMO, this Perl kind of jump is even better design than C's "break" and "continue", because it makes clear what loop we break or continue, and it makes it more solid in the face of code changes. (Besides, it also allows to break or continue an outer loop.)
There are pundits who don't like break/continue and the like, but at some point there is a tradeoff to make between rules of thumb and readability, and a well-chosen break/continue or even goto may become more readable than "politically correct" code.
break/last and continue/next ARE gotos. I don't understand why anyone would go to such lengths to avoid a keyword yet use a different keyword that does the same thing...
4.4.4. Loop Control
We mentioned that you can put a LABEL on a loop to give it a name. The loop's LABEL identifies the loop for the loop-control operators next, last, and redo. The LABEL names the loop as a whole, not just the top of the loop. Hence, a loop-control operator referring to the loop doesn't actually "go to" the loop label itself. As far as the computer is concerned, the label could just as easily have been placed at the end of the loop. But people like things labeled at the top, for some reason.
Programming Perl

Nested Loop / Loop Control tutorial [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I'm looking for a good tutorial on writing and designing loops. I understand the basics of loops but nested loops give me a lot of trouble. To give you and idea, the following pattern below was kind of difficult for me to figure out.
1
12
123
1234
12345
123456
Loops
A loop is a construct that enables a set of instructions to be executed more than once.
There are several loop constructions:
zero or more
These loops have the check at the begining of an iteration and as such will be executed 0 or more times. A while loop is an example.
one or more
These loops have the check at the end of the iteration and as such will be executed at least once. A do while loop is an example.
Loops with counters
These loops have a counter that counts from a certain number to an other number. The number can be used inside the loop (for example to access a field of an array).
Loops with an iterator
These loops use an iterator to loop through a certain structure.
Endless loops
These loops have no end. But of course nothing is forever, so the loop often contains a hidden mechanism.
Nested loops
If you understand single loops, nested loops can be difficult. But you need to focus on one loop at a time.
Lets take your example:
1
12
123
1234
12345
123456
Ok, lets first look at the lines.
The first line has a single 1
The second line counts from 1 to 2
The third line counts from 1 to 3
...
Generally: the n th line counts from 1 to n.
Great, no we have the individual line. But let's now look at all lines.
the first has n=1
the second has n=2
the third has n=3
...
Hm, so we can use the loop counter of the outer loop as the n in the inner loop:
for n = 1 to 6
s = ''
for i = 1 to n // use the loopcounter of the outer loop
s = s + char(i)
end for
out s
end for
Check out:
http://mathbits.com/mathbits/compsci/looping/nested.htm
http://tldp.org/LDP/abs/html/nestedloops.html
http://www.actionscript.org/resources/articles/5/1/The-power-of-nested-loops/Page1.html
In general (language-neutral) terms, the basic logic is quite straightforward. Where it can get more complex is if an inner loop terminates early & the manner of the break. It may cause the outer loop to move to the next value, or it may completely exit the outer loop as well.
The best way to learn this is to try out different cases to see how they behave, and read up on the ways to exit from loops.
How about these:
Nested Loops
The Power of Nested Loops
or on YouTube "SQL Joins, nested loops and all that in less than 6 minutes" at http://www.youtube.com/watch?v=SmDZaH855qE
I don't remember seeing any "loop design" centred tutorials when I was learning to program.
You will get a grasp of loops if you just start tackling on different problems and algorithms. Look for matrix problems, you will need nested loops there for instance...
I'm unaware of any tutorials on this subject, but I suggest you try Google. Also, the fact that you were able to figure out your example probably means that you don't need a tutorial as much as you need practice. Nested loops are somewhat mind-warping when you first encounter them. You might also want to look for references/tutorials pertaining to recursion, which is a related concept. Remember, practice makes perfect!
Check out the MIT Course Material. Also consider getting a Safari subscription, a cheap way of getting some good learning books.
This MIT course points to Loops on the python wiki.
I found that working it out on paper, listing the variables helps in learning how this works.
declare
s varchar2(10);
begin
for n in 1..5 loop
s:='';
for i in 1..n loop
s:=s||(i);
end loop;
dbms_output.put_line(s);
end loop;
end;

Resources