Related
I would like to know if there is a better more efficient way to use if statements rather than just long lines of
if(){
//code
}else if(){
//code
} else{
//code
}
I've done some research on the site and I found this:
If you have only 2 values, I strongly suggest to use the code you posted, because is likely the most readable, elegant and fast code possible (IMHO).
But if you have more cases like that and more complicated, you could
think to use a switch statement:
switch (el.type)
{
case ElementType.Type1:
case ElementType.Type2:
case ElementType.Type3:
//code here
break;
case ElementType.Type4:
case ElementType.Type5:
//code here
break;
case ElementType.Type6:
//code here
break;
}
that translated in if statements would be:
if (el.type == ElementType.Type1 ||
el.type == ElementType.Type2 ||
el.type == ElementType.Type3 )
{
// code here
}else if(el.type == ElementType.Type4 ||
el.type == ElementType.Type5)
{
// code here
}else if(el.type == ElementType.Type6)
{
// code here
}
They're perfectly equal to me, but the switch seems more readable/clearer, and you need to type less (i.e. it's "shorter" in term of code length) :)
Although I don't quite understand what it is telling me, is it saying that a switch statement is a better use for long if statements or?
To have some context surrounding my problem, I have a Windows Forms application with some radio buttons - A questionnaire if you will - I want to know if there is more efficient ways that reduces repetitive unnecessary lines of code and replaces them with short code that does the same job.
The goal should be more readable / clearer code, which does not always mean the shortest statement.
If you have very complex logic, with lots of nested if / else branches, try to split it in smaller, simpler routines.
Switch statements as well as many if-else statements are often a sign of the smelly design.
Consider refactoring into a more object-oriented design
If-else not much more readable than switch-case and vice-versa.
You could apply CoR pattern.
Here you will fine one of .NET implementations.
When you combine this with IoC container you may achieve very flexible architecture...
switch statements are not only easier to read, they are easier for the compiler to optimize because they explicitly specify one value you are triggering all the code off of. The compiler can easily optimize this using a hash or a jump table rather than a sequence of comparisons, making it much faster (when it can do so). Technically, it could detect that the if statements are the same thing, but may or may not be sophisticated enough to do so. So, if you have 256 separate cases triggering off the value of a byte, a switch can be compiled into a hard coded array of code offsets (each entry in the array is the offset of the code handling that case), and no comparison is done at all because it can just use the byte value as an index into the hard coded array and jump to the correct code. This is much faster than doing 255 (or 256) compares.
Switches using string values are also handled specially, using hash codes for better performance. You may be able to do something similar explicitly, but your code will be much less readable.
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 9 years ago.
Is it a bad practice to use break statement inside a for loop?
Say, I am searching for an value in an array. Compare inside a for loop and when value is found, break; to exit the for loop.
Is this a bad practice? I have seen the alternative used: define a variable vFound and set it to true when the value is found and check vFound in the for statement condition. But is it necessary to create a new variable just for this purpose?
I am asking in the context of a normal C or C++ for loop.
P.S: The MISRA coding guidelines advise against using break.
No, break is the correct solution.
Adding a boolean variable makes the code harder to read and adds a potential source of errors.
Lots of answers here, but I haven't seen this mentioned yet:
Most of the "dangers" associated with using break or continue in a for loop are negated if you write tidy, easily-readable loops. If the body of your loop spans several screen lengths and has multiple nested sub-blocks, yes, you could easily forget that some code won't be executed after the break. If, however, the loop is short and to the point, the purpose of the break statement should be obvious.
If a loop is getting too big, use one or more well-named function calls within the loop instead. The only real reason to avoid doing so is for processing bottlenecks.
You can find all sorts of professional code with 'break' statements in them. It perfectly make sense to use this whenever necessary. In your case this option is better than creating a separate variable just for the purpose of coming out of the loop.
Using break as well as continue in a for loop is perfectly fine.
It simplifies the code and improves its readability.
Far from bad practice, Python (and other languages?) extended the for loop structure so part of it will only be executed if the loop doesn't break.
for n in range(5):
for m in range(3):
if m >= n:
print('stop!')
break
print(m, end=' ')
else:
print('finished.')
Output:
stop!
0 stop!
0 1 stop!
0 1 2 finished.
0 1 2 finished.
Equivalent code without break and that handy else:
for n in range(5):
aborted = False
for m in range(3):
if not aborted:
if m >= n:
print('stop!')
aborted = True
else:
print(m, end=' ')
if not aborted:
print('finished.')
General rule: If following a rule requires you to do something more awkward and difficult to read then breaking the rule, then break the rule.
In the case of looping until you find something, you run into the problem of distinguishing found versus not found when you get out. That is:
for (int x=0;x<fooCount;++x)
{
Foo foo=getFooSomehow(x);
if (foo.bar==42)
break;
}
// So when we get here, did we find one, or did we fall out the bottom?
So okay, you can set a flag, or initialize a "found" value to null. But
That's why in general I prefer to push my searches into functions:
Foo findFoo(int wantBar)
{
for (int x=0;x<fooCount;++x)
{
Foo foo=getFooSomehow(x);
if (foo.bar==wantBar)
return foo;
}
// Not found
return null;
}
This also helps to unclutter the code. In the main line, "find" becomes a single statement, and when the conditions are complex, they're only written once.
There is nothing inherently wrong with using a break statement but nested loops can get confusing. To improve readability many languages (at least Java does) support breaking to labels which will greatly improve readability.
int[] iArray = new int[]{0,1,2,3,4,5,6,7,8,9};
int[] jArray = new int[]{0,1,2,3,4,5,6,7,8,9};
// label for i loop
iLoop: for (int i = 0; i < iArray.length; i++) {
// label for j loop
jLoop: for (int j = 0; j < jArray.length; j++) {
if(iArray[i] < jArray[j]){
// break i and j loops
break iLoop;
} else if (iArray[i] > jArray[j]){
// breaks only j loop
break jLoop;
} else {
// unclear which loop is ending
// (breaks only the j loop)
break;
}
}
}
I will say that break (and return) statements often increase cyclomatic complexity which makes it harder to prove code is doing the correct thing in all cases.
If you're considering using a break while iterating over a sequence for some particular item, you might want to reconsider the data structure used to hold your data. Using something like a Set or Map may provide better results.
break is a completely acceptable statement to use (so is continue, btw). It's all about code readability -- as long as you don't have overcomplicated loops and such, it's fine.
It's not like they were the same league as goto. :)
It depends on the language. While you can possibly check a boolean variable here:
for (int i = 0; i < 100 && stayInLoop; i++) { ... }
it is not possible to do it when itering over an array:
for element in bigList: ...
Anyway, break would make both codes more readable.
I agree with others who recommend using break. The obvious consequential question is why would anyone recommend otherwise? Well... when you use break, you skip the rest of the code in the block, and the remaining iterations. Sometimes this causes bugs, for example:
a resource acquired at the top of the block may be released at the bottom (this is true even for blocks inside for loops), but that release step may be accidentally skipped when a "premature" exit is caused by a break statement (in "modern" C++, "RAII" is used to handle this in a reliable and exception-safe way: basically, object destructors free resources reliably no matter how a scope is exited)
someone may change the conditional test in the for statement without noticing that there are other delocalised exit conditions
ndim's answer observes that some people may avoid breaks to maintain a relatively consistent loop run-time, but you were comparing break against use of a boolean early-exit control variable where that doesn't hold
Every now and then people observing such bugs realise they can be prevented/mitigated by this "no breaks" rule... indeed, there's a whole related strategy for "safer" programming called "structured programming", where each function is supposed to have a single entry and exit point too (i.e. no goto, no early return). It may eliminate some bugs, but it doubtless introduces others. Why do they do it?
they have a development framework that encourages a particular style of programming / code, and they've statistical evidence that this produces a net benefit in that limited framework, or
they've been influenced by programming guidelines or experience within such a framework, or
they're just dictatorial idiots, or
any of the above + historical inertia (relevant in that the justifications are more applicable to C than modern C++).
In your example you do not know the number of iterations for the for loop. Why not use while loop instead, which allows the number of iterations to be indeterminate at the beginning?
It is hence not necessary to use break statemement in general, as the loop can be better stated as a while loop.
I did some analysis on the codebase I'm currently working on (40,000 lines of JavaScript).
I found only 22 break statements, of those:
19 were used inside switch statements (we only have 3 switch statements in total!).
2 were used inside for loops - a code that I immediately classified as to be refactored into separate functions and replaced with return statement.
As for the final break inside while loop... I ran git blame to see who wrote this crap!
So according to my statistics: If break is used outside of switch, it is a code smell.
I also searched for continue statements. Found none.
It's perfectly valid to use break - as others have pointed out, it's nowhere in the same league as goto.
Although you might want to use the vFound variable when you want to check outside the loop whether the value was found in the array. Also from a maintainability point of view, having a common flag signalling the exit criteria might be useful.
I don't see any reason why it would be a bad practice PROVIDED that you want to complete STOP processing at that point.
In the embedded world, there is a lot of code out there that uses the following construct:
while(1)
{
if (RCIF)
gx();
if (command_received == command_we_are_waiting_on)
break;
else if ((num_attempts > MAX_ATTEMPTS) || (TickGet() - BaseTick > MAX_TIMEOUT))
return ERROR;
num_attempts++;
}
if (call_some_bool_returning_function())
return TRUE;
else
return FALSE;
This is a very generic example, lots of things are happening behind the curtain, interrupts in particular. Don't use this as boilerplate code, I'm just trying to illustrate an example.
My personal opinion is that there is nothing wrong with writing a loop in this manner as long as appropriate care is taken to prevent remaining in the loop indefinitely.
Depends on your use case. There are applications where the runtime of a for loop needs to be constant (e.g. to satisfy some timing constraints, or to hide your data internals from timing based attacks).
In those cases it will even make sense to set a flag and only check the flag value AFTER all the for loop iterations have actually run. Of course, all the for loop iterations need to run code that still takes about the same time.
If you do not care about the run time... use break; and continue; to make the code easier to read.
On MISRA 98 rules, that is used on my company in C dev, break statement shall not be used...
Edit : Break is allowed in MISRA '04
Ofcourse, break; is the solution to stop the for loop or foreach loop. I used it in php in foreach and for loop and found working.
I think it can make sense to have your checks at the top of your for loop like so
for(int i = 0; i < myCollection.Length && myCollection[i].SomeValue != "Break Condition"; i++)
{
//loop body
}
or if you need to process the row first
for(int i = 0; i < myCollection.Length && (i == 0 ? true : myCollection[i-1].SomeValue != "Break Condition"); i++)
{
//loop body
}
This way you can have a singular body function without breaks.
for(int i = 0; i < myCollection.Length && (i == 0 ? true : myCollection[i-1].SomeValue != "Break Condition"); i++)
{
PerformLogic(myCollection[i]);
}
It can also be modified to move Break into its own function as well.
for(int i = 0; ShouldContinueLooping(i, myCollection); i++)
{
PerformLogic(myCollection[i]);
}
I found an empty for statement in an existing bit of code and I'm wondering what it does and is it "safe". It just feels wrong.
for(;;)
{
//some if statements and a case statement
}
Thanks!
This is one way of creating an infinite loop. It's a regular for loop, but with empty initialization, condition, and increment expressions. Because the condition expression is a no-op, the loop never exits. It's perfectly "safe" assuming it has a terminating condition (a break or return statement [or even a goto, I suppose]) somewhere.
Personally, I prefer to write infinite loops with whiles:
while (true)
{
//some statements and a case statement
}
(because for is for iteration and while is for repetition).
However, after reading this question (linked by #jailf), I now prefer while (42) { ... }.
It's equivalent as having an infinite loop:
while (true) {
}
It's safe. You need to provide an external exit mechanism though. I.E., with a break within the for loop.
This is a common idiom for an indefinite or infinite loop. You purposely might have an indefinite loop if you are looking for a condition that is not finite at the beginning -- such as user input or the end of a file of unknown size. You might also see while(1) or while(true) for the same thing. It says 'do this thing { whatever } until there is no more...'
Inside that loop structure is probably a conditional and a break statement, such as:
for(;;)
{
Console.Write("Enter your selection (1, 2, or 3): ");
string s = Console.ReadLine();
int n = Int32.Parse(s);
switch (n)
{
case 1:
Console.WriteLine("Current value is {0}", 1);
break;
case 2:
Console.WriteLine("Current value is {0}", 2);
break;
case 3:
Console.WriteLine("Current value is {0}", 3);
break;
default:
Console.WriteLine("Sorry, invalid selection.");
break;
}
if(n==1 || n==2 || n==3)
break; // out of the for(;;) loop
}
The key whether is it "safe" or not is to figure out the logic of how you leave that loop, or your indefinite loop will become an unintended infinite loop and a bug.
More at the C# site for for: HERE
All of the expressions of the for
statement are optional; for example,
the following statement is used to
write an infinite loop:
> for (; ; ) {
> // ... }
Taken from MSDN
It's the same as while (true) { /**/ } ... infinite loop until break or return or similar occurs.
All it really "does" is look ugly IMO ;)
This has been asked multiple times on SO. The best discussion on the topic is at the following link:
Is "for(;;)" faster than "while (TRUE)"? If not, why do people use it?
It's valid syntax for an infinite loop. You need to "break;" out of it. This was popular back in the C++ days IIRC.
As far as being safe, you're right in feeling "wrong" about this. Usually there would be an "if" condition inside where you would decide if you continue or break the loop. If you don't verify all execution paths it could very well lead to an infinite loop. I would try and do this some other way.
It's sometimes called a "forever" loop, because that's what it does. Look for either a break; or return; statement inside the loop or for the loop to be wrapped in a try/catch block. Personally, I try avoid that kind of thing.
Were there any break, return, or throw statements? That‘s the only way out. Is it safe? It depends if you feel safe inside an infinite loop. Some applications need one.
This is very common on embedded systems without an operating system. If your program terminates, there is no underlying system to handel that. So mostly there's one huge infinite loop in which most of the operations are handled.
I've seen this on occasion in books I've read. But I've found no explanation.
for (;;)
{
// Do some stuff.
}
Is it kind of like "while(true)"? Basically an endless loop for polling or something? Basically something you'd do until you intentionally break the loop?
Is it kind of like "while(true)"?
Yes. It loops forever.
Also note the comment by Andrew Coleson:
Languages like C don't have built-in boolean primitives, so some people prefer for(;;) over while(1)
Yes.
In a for if nothing is provided:
The initialisation does nothing.
The condition is always true
The count statement does nothing
It is equivalent to while(true).
You are correct. This is a common C# idiom for an endless loop.
Correct. Note that the braces of a for loop contain three parts:
Initialization code
A condition for continuing the loop
Something that gets executed for each loop iteration
With for(;;), all of these are empty, so there is nothing done to initialize the loop, there is no condition to keep it running (i.e. it will run indefinitely) and nothing that gets executed for each iteration except the loop's content.
Yes, It is an infinite loop.
If I recall correctly it's use over "while(true)", is it more resembles "for(;;) //ever"
Take a look at a for loop.
for ( initialization ; condition ; increment )
1) initialization - set a counter variable here
2) condition - keep looping until the counter variable meets the condition
3) increment - increment the counter
If there is no condition, a loop will go on forever. If it does such, then there is no need for a counter. Therefore
for(;;)
Yes, it's an endless loop, just like while(true).
It's the slightly preferred convention, probably because it's shorter.
There's no efficiency difference at all.
Loop forever.
Yes, it's an infinite loop. Same idea/effect as doing while(true) { ... }
Inifinite loop
like saying
while (0<1)
To be precise, any for loop without anything between the semicolons will loop forever (until terminated by some other means), because it has no defined invariant.
It doesn't have an end condition, so it will loop forever until it find a break, as you already guessed.
I might also add that it looks like 2 smiley faces winking at you
for (; ;)
maybe that's why some people like to use it.
Yes, it loops forever.
But the reason why you should use
for(;;)
instead of
while(true)
is that
while(true)
will give you a compiler warning "conditional expression constant", while the for-loop does not. At least you'll get such a compiler warning in the highest warning level.
Yes! .
Often used in embedded programming.
-setup interrupts and timers.
-then loop forever.
When an interrupt or timer occurs that will be handled.
One of Steve McConnell's checklist items is that you should not monkey with the loop index (Chapter 16, page 25, Loop Indexes, PDF format).
This makes intuitive sense and is a practice I've always followed except maybe as I learned how to program back in the day.
In a recent code review I found this awkward loop and immediately flagged it as suspect.
for ( int i=0 ; i < this.MyControl.TabPages.Count ; i++ )
{
this.MyControl.TabPages.Remove ( this.MyControl.TabPages[i] );
i--;
}
It's almost amusing since it manages to work by keeping the index at zero until all TabPages are removed.
This loop could have been written as
while(MyControl.TabPages.Count > 0)
MyControl.TabPages.RemoveAt(0);
And since the control was in fact written at about the same time as the loop it could even have been written as
MyControl.TabPages.Clear();
I've since been challenged about the code-review issue and found that my articulation of why it is bad practice was not as strong as I'd have liked. I said it was harder to understand the flow of the loop and therefore harder to maintain and debug and ultimately more expensive over the lifetime of the code.
Is there a better articulation of why this is bad practice?
I think your articulation is great. Maybe it can be worded like so:
Since the logic can be expressed much
clearer, it should.
Well, this adds confusion for little purpose - you could just as easily write:
while(MyControl.TabPages.Count > 0)
{
MyControl.TabPages.Remove(MyControl.TabPages[0]);
}
or (simpler)
while(MyControl.TabPages.Count > 0)
{
MyControl.TabPages.RemoveAt(0);
}
or (simplest)
MyControl.TabPages.Clear();
In all of the above, I don't have to squint and think about any edge-cases; it is pretty clear what happens when. If you are modifying the loop index, you can quickly make it quite hard to understand at a glance.
It's all about expectation.
When one uses a loopcounter, you expect that it is incremented (decremented) each iteration of the loop with the same amount.
If you mess (or monkey if you like) with the loop counter, your loop does not behave like expected. This means it is harder to understand and it increases the chance that your code is misinterpreted, and this introduces bugs.
Or to (mis) quote a wise but fictional character:
complexity leads to misunderstanding
misunderstanding leads to bugs
bugs leads to the dark side.
I agree with your challenge. If they want to keep a for loop, the code:
for ( int i=0 ; i < this.MyControl.TabPages.Count ; i++ ) {
this.MyControl.TabPages.Remove ( this.MyControl.TabPages[i] );
i--;
}
reduces as follows:
for ( int i=0 ; i < this.MyControl.TabPages.Count ; ) {
this.MyControl.TabPages.Remove ( this.MyControl.TabPages[i] );
}
and then to:
for ( ; 0 < this.MyControl.TabPages.Count ; ) {
this.MyControl.TabPages.Remove ( this.MyControl.TabPages[0] );
}
But a while loop or a Clear() method, if that exists, are clearly preferable.
I think you could build a stronger argument by invoking Knuth's concepts of literate programming, that programs should not be written for computers, but to communicate concepts to other programmers, thus the simpler loop:
while (this.MyControl.TabPages.Count>0)
{
this.MyControl.TabPages.Remove ( this.MyControl.TabPages[0] );
}
more clearly illustrates the intent - remove the first tab page until there are none left. I think most people would grok that much quicker than the original example.
This might be clearer:
while (this.MyControl.TabPages.Count > 0)
{
this.MyControl.TabPages.Remove ( this.MyControl.TabPages[0] );
}
One argument that could be used is that it is much more difficult to debug such code, where the index is being changed twice.
The original code is highly redundant to bend the action of the for-loop to what is necessary. The increment is unnecessary, and balanced by the decrement. Those should be PRE-increments, not POST-increments as well, because conceptually the post-increment is wrong. The comparison with the tabpages count is semi-redundant since that's a hackish way of checking that the container is empty.
In short, it's unnecessary cleverness, it adds rather than removes redundancy. Since it can be both obviously simpler and obviously shorter, it's wrong.
The only reason to bother with an index at all would be if one were selectively erasing things. Even in that case, I would think it preferable to say: i=0;
while(i < MyControl.Tabpages.Count)
if (wantToDelete(MyControl.Tabpages(i))
MyControl.Tabpages.RemoveAt(i);
else
i++;rather than jinxing the loop index after each removal. Or, better yet, have the index count downward so that when an item is removed it won't affect the index of future items needing removal. If many items are deleted, this may also help minimize the amount of time spent moving items around after each deletion.
I think pointing out the fact that the loop iteratations is beeing controled not by the "i++" as anyone would expect but by the crazy "i--" setup should have been enough.
I also think that altering the the state of "i" by evaluating the count and then altering the count in the loop may also lead to potential problems. I would expect a for loop to generally have a "fixed" number of iterations and the only part of the for loop condition that changes to be the loop variable "i".