Endless loops and early return statements

I have a simple console application that displays a menu and waits for user input. After performing the appropriate action, the whole process is repeated. The program exits when a specific line is entered. This is implemented using an infinite loop and an early return statement:

int main() { while (true) { OutputMenu(); string UserChoice; cin >> UserChoice; // ... if (UserChoice == "exit") return 0; } } 

According to my teacher, it is bad practice to use an infinite loop and tear my way out of it using the return statement. He suggests something like the following:

 int main() { bool ShouldExit = false; while (!ShouldExit) { OutputMenu(); string UserChoice; cin >> UserChoice; // ... if (UserChoice == "exit") ShouldExit = true; } return 0; } 
  • Is it really a bad idea to use an infinite loop and an early return statement?
  • If so, is there a technical reason or is it just bad practice?
+4
source share
13 answers

This may be one of those rare cases where do...while is appropriate. I do not add additional logical state variables unless they really make the code more understandable.

 int main() { string UserChoice; do { OutputMenu(); cin >> UserChoice; // ... } while (UserChoice != "exit"); } 

However, for a user input loop, I usually do a function that returns whether the input was successful. In this case, the code can easily end in an infinite loop if cin closes.

eg.

 bool GetNonExitInput( std::istream& in, std::string& s ) { OutputMenu(); in >> s; return in.good() && s != "exit"; } int main() { std::string UserChoice; while (GetNonExitInput(std::cin, UserChoice)) { // ... } } 
+11
source

Indeed, all is well, but you need to do what your professor wants. You will find that in industry this is the same. Some companies may have a coding standard that dictates curly braces on a new line, while others want them to start on a line that starts with a block. There is no real reason to prefer each other, so it’s best to go with what the leader wants.

+7
source

The only difference between the two approaches is that in the second approach, you can still do something after exiting the while , while in the first approach, you return from the function itself; you cannot do anything after while .

However, I would suggest this simple code: instead of saving a variable, you can also use break as follows:

 while (true) { //your code if (UserChoice == "exit") break; //your code } 

The ShouldExit variable ShouldExit no longer needed!

+6
source

It depends on the language. If you write in C, then the philosophy of “one record, one way out” makes sense - you need one place where you clear the resources used by the function so that you don’t have the opportunity to forget later. If you are in C ++ then you should still use RAII for cleanup, in which case I totally disagree with your teacher. Use return as needed to make the code as clear as possible.

(Although I would use for (;;) instead of while (true) in C ++ to generate an infinite loop)

+5
source

Using a managed variable, you can process the exit conditions (the code after that) before exiting the function.

+2
source

In my opinion, both methods are good, but the second is "prettier."

When programming, it is important to write code in the simplest way that you can think of, and make it easier for other programmers to understand your code if you are replaced or for some other reason.

There are no problems with the complex with your two codes, so they are both beautiful, as I said, but I think I don’t like the first code, this is using the "return" statment without the real need for a "return", here.

There is another way to write this code, better than your path (in my opinion), but not better than your teacher.

 int main() { bool ShouldExit = false; while ( true ) { OutputMenu(); string UserChoice; cin >> UserChoice; // ... if (UserChoice == "exit") break; } } 

Another important reason why I don’t like your first code and my code above, because of the use of an infinite loop, when you use yourself in infinite loops, it is only a matter of time until you make more complex programs with basic errors in him.

Again - everything that I wrote, in my opinion, and not the truth of the gospel.

Rotem

+2
source

Technically, there is not much there until there is a code that you skip with return.

However, your teacher suggestion is more readable, if only because of the obvious meaning of “ShouldExit”.

+1
source

I think your teacher means that the exit condition can be easily maintained. This is due to code cleanup after the while loop. If you make a hard return, then everything after the while loop will fail. This can be prevented by breaking instead of returning.

 int main() { //create a file while (true) { OutputMenu(); string UserChoice; cin >> UserChoice; //write UserChoice to file // ... if (UserChoice == "exit") return 0; } //close file } 

//close file will not execute!

+1
source

The break statement is specifically designed to exit the loop.

+1
source

I usually prefer what your teacher suggested, simply because it is easier to read and understand the conditions for stopping the cycle.
If you have an infinite loop with the return statement, it's a little harder for those who haven't written the code to go through the code and figure out when the program gets into the return .

Also, I usually don't like early returns at all, because for someone who supports the code, introduce errors, like this:

 int main() { // code added by some other programmer: importantInitialization(); while (true) { OutputMenu(); // code added by some other programmer: Something *st = new Something(); string UserChoice; cin >> UserChoice; // ... if (UserChoice == "a") runA(); else if (UserChoice == "b") runB(); else if (UserChoice == "c") runC(); else if (UserChoice == "d") runD(); else if (UserChoice == "exit") return 0; else if (UserChoice == "help") showHelp(); // code added by some other programmer: delete st; // this would not run on the last loop } // code added by some other programmer: importantCleanUp(); // this would never run } 

Of course, it’s easy to see problems in this particular case, but if you save a more complex function, you can see how an earlier return statement can make it even more prone to errors of lack of attention, like this.

+1
source

I think that time (true) with a break is best for several reasons. Representing a variable to preserve the exit condition is an error prone; a larger number of variables means that more can go wrong. Also, the break statement is specifically designed to exit loops. Finally, contrary to for (;;), while (true) is clean, readable, and concise, where for (;;) is trying to be smart for no good reason.

At the added point, to increase readability and understanding, set the exit conditions closest to the top of the cycle, as much as possible:

 while (true) { OutputMenu(); string UserChoice; cin >> UserChoice; if (UserChoice == "exit") break; // process other options here } 
+1
source

In terms of state analysis, a procedure using a local flag is equivalent to the same code in duplicate, with one copy corresponding to true and another copy equivalent to a flag that is false, and any code that changes the state of a flag jumping between them. If there are n flags, the equivalent will be 2 ^ n copies of the code (although if some flags are mutually exclusive, some of them may be inaccessible and irrelevant).

Although flags are the most practical way to do something, they add complexity to the code. When complexity is really necessary, flags can be the cleanest way to provide it. When there is a clean and practical way of writing code that avoids flags, you need to do this. Of course, there are times when it may not be clear whether to use or avoid the flag (e.g.

  flag = condition_which_must_be_tested_here ();
   action_which_will_disturb_the_condition ();
   if (flag)
     do_something ();
   else
     do_something_else ();

vs

  if (condition_which_must_be_tested_here ())
   {    
     action_which_will_disturb_the_condition ();
     do_something ();
   }
   else
   {    
     action_which_will_disturb_the_condition ();
     do_something_else ();
   }

but in cases where the code cannot be written without a flag and should not duplicate anything, such a version is usually preferable.

+1
source

I philosophically object to while(true) . It means “forever cycle” and you never want to go in cycles forever.

On the other hand, I also philosophically object to logical variables that simply capture a state that can be detected in other ways. There arises an error in that it cannot always be correctly synchronized with the state that it should reflect. In this case, I would prefer code like:

 int main() { string UserChoice = "not started"; // or empty string while (UserChoice != "exit") { OutputMenu(); string UserChoice; cin >> UserChoice; // ... } return 0; } 
0
source

Source: https://habr.com/ru/post/1332774/


All Articles