Skip to main content
GameDev.net gamedev.net
🔒 Locked

iteration statements, control flow

Started by algumacoisaqualquer Jul 25, 2007 at 6:30 AM 15 replies 3.6k views
Original Post
algumacoisaqualquer
algumacoisaqualquer
The iteration statements are discussed in the page 79 of book zero. I have some doubts about them (I've had them since C++ actually)... First of, is there some way to get out of two nested loops without a goto? Something like break, but break only works in the currently block, right? Also, will break work out for any block we are? Even in blocks following if(){}, for instance? I have some doubts on swicthes also... I believe that, like in C++, the cases must be constants (literals??), right? Why is that? I'm assuming this is because the way a swicth block is turned into assembly code (seeing how the flow of these structures is somewhat different), but that is only a guess. Thank you!
Mike.Popoloski
Mike.Popoloski
Who cares if you can only break out of one? You could do something like this quite easily:

for( int i = 0; i < 5; i++ ){    bool done = false;    for( int j = 0; j < 5; j++ )    {        if( iWantToBreakOutOfBothLoops )        {            done = true;            break;        }    }    if( done )        break;}
Mike Popoloski | Journal | SlimDX
algumacoisaqualquer
algumacoisaqualquer
Quote:
Original post by Mike.Popoloski
Who cares if you can only break out of one? You could do something like this quite easily:

*** Source Snippet Removed ***

I see. I know that generaly performace wouldn't be a major consideration is most of these cases, but I believe the following code would be sligthly more efficient:
for( int i = 0; i < 5; i++ ){    for( int j = 0; j < 5; j++ )    {        if( iWantToBreakOutOfBothLoops )        {            goto we_are_done;        }    }}we_are_done:

I was wondering if there was some way to do it without using goto, but I guess that this is exactly the reason they exist (I mean, if I want to create a program structure that relies in jumping from one point to another, I shouldn't complain when I need a goto to do so). But as it was said in the previous tread, this shows us how bad gotos can be.

I get your point though: there are ways to do it without recuring to jump statements, and they are probably much safer.

On the other hand, your example shows us that the break; statement won't break out of the currently block it is in (i.e a block following an if()), but rather from the last iteration statement it belonged... I have no idea why.

Thanks for the answer!
Spoonbender
Spoonbender
Quote:
Original post by algumacoisaqualquer
I see. I know that generaly performace wouldn't be a major consideration is most of these cases, but I believe the following code would be sligthly more efficient:

If we assume the compiler is braindead, yes, which isn't usually the case. [wink]

[opinion]
A better argument would be that the above isn't all that pretty to look at. Generally speaking, if you want nested loops, and want to be able to break out of them, refactor and put the inner loop(s) into a separate function.
Or put the outer loop in its own function, and simply return when you want to break out.
bool inner(){    for( int j = 0; j < 5; j++ )    {        if( iWantToBreakOutOfBothLoops )        {            return false;        }    }    return true;}for( int i = 0; i < 5; i++ ){    if (!inner){ break; }}

or
void outer(){    for( int i = 0; i < 5; i++ )    {        for( int j = 0; j < 5; j++ )        {            if( iWantToBreakOutOfBothLoops )            {                return;            }        }    }}


Quote:

I was wondering if there was some way to do it without using goto, but I guess that this is exactly the reason they exist (I mean, if I want to create a program structure that relies in jumping from one point to another, I shouldn't complain when I need a goto to do so).

No, then you should use functions, which... jump from one point to another. That's what they're for.

[Edited by - Spoonbender on July 25, 2007 8:38:21 AM]
Telastyn
Telastyn
[opinion]
I agree on using return for cases such as that. In rare cases where that is either infeasible or kinda icky (and you've reviewed your design to ensure there isn't a cleaner alternative) placing that conditional in the loop bits is (imo) easier to follow and change as necessary:
for( int x = 0; x < 10 && someCondition; ++x){    for( int y = 0; y < 42 && someCondition; ++y){        // do stuff that might invalidate someCondition    }}


That said, the return design is almost always preferable and if your design doesn't allow that easily, I'd check to make sure your methods/classes aren't trying to do too much.
savagemonitor
savagemonitor
Here's an example that would allow you to break out of both loops:

[source lang=C#]for(int i = 0; i< 10; i++)                for (int j = 0; j < 10; j++)                {                    if (j == 2)                    {                        Console.Out.WriteLine("Break out of inner loop");                        i = 11;                        break;                    }                }


[opinion]However, when I'm searching for something in a doubly nested loop, I like to hand that off to a function so that I can just return out of the function rather than dealing with the above structure. In fact, I usually only reserve break statements for while loops or for loops without other loops nested underneath.[/opinion]

I don't know on your question about switches.
SixPack00
SixPack00
[opinion]
One of the concepts of structured programming is single entry, single exit. I've used this in my programming career. Using gotos or convoluted logic to "break" out of an inner (and outer) loop is only going to get you into trouble.

If you look hard enough, you should be able to write your logical conditions such that you don't need to "break" out. Use of a FOR loop means you know how many times you will loop. If it varies and you need to break out of the loop, then use a do while.

When I was a rookie programmer, I spent my first year doing maintenance. You can't believe the convoluted logic some people can come up with. One thing I learned is you code for maintenance. Most programs stick around longer than you might think and some poor schmuck is going to have to maintain it when something goes wrong. Sometimes that's you. You want straight forward, clean code. Something a rookie could understand. Something you can understand when you get called at 3 AM in the morning and need to fix it right away. Cause we all know...time is money.

If you don't do it right, there are plenty of others who will.
TheTroll
TheTroll
[opinion]
Back in the "old" days we did a lot of optimization for memory and processing because both were limited. Now days, with the current processors and memory it is
not as big as issue.

So some of the "convoluted" code that might find could have been done to try to speed things up or cut down on memory usage. It could also just be bad coding.

I think for the most part you try to make the code as readable as possible. Yes, you should care about performance but you need to understand where you can make gains, and where you just don't worry about it.
[/opinion]

theTroll
algumacoisaqualquer
algumacoisaqualquer
Ok, thank you guys for the answers!

I mean, I have to confess that there is something on jumping inside the code that I like more than I should (or more than it's healthy). But this could be because of bad coding habits though. However, I don't really use gotos in my code, or things like that, but I was curious to know the inner workings of these features.

Anyway, the language specification was very clarifying in these aspects. Specially these parts of chapter 8: Selection Statements, Iteration Statements, Jump Statements and so forth - I found them a lot easier to read then the book normally is. The part of the break; statement says:
Quote:

The break statement exits the nearest enclosing switch, while, do, for, or foreach statement.
break-statement:
break ;
The target of a break statement is the end point of the nearest enclosing switch, while, do, for, or foreach statement. If a break statement is not enclosed by a switch, while, do, for, or foreach statement, a compile-time error occurs.
When multiple switch, while, do, for, or foreach statements are nested within each other, a break statement applies only to the innermost statement. To transfer control across multiple nesting levels, a goto statement (§8.9.3) must be used.
A break statement cannot exit a finally block (§8.10). When a break statement occurs within a finally block, the target of the break statement must be within the same finally block; otherwise, a compile-time error occurs.


Of course, this is a language specification, so it doesen't says anything about good or bad coding habits (I guess that's the great thing about a workshop), but it contains some aditional information.
Again, thank you all!
Spoonbender
Spoonbender
Quote:
Original post by algumacoisaqualquer
Ok, thank you guys for the answers!

I mean, I have to confess that there is something on jumping inside the code that I like more than I should (or more than it's healthy). But this could be because of bad coding habits though.

Or it just be that you're not familiar enough with the other language constructs :)
Jumping around in code is not in itself a bad thing. It's pretty fundamental for code reuse, for refactoring, for writing readable code.

The thing is, you should usually use functions to do your jumping around, not goto statements.
When you think about it, a function is exactly that, a jump to another piece of code. So why not use that instead?
If you need to jump to another bit of code, then it should probably be a separate function. That'll make it much more readable too.
simesf
simesf
Quote:
Original post by TheTroll
[opinion]
Back in the "old" days we did a lot of optimization for memory and processing because both were limited. Now days, with the current processors and memory it is
not as big as issue.

So some of the "convoluted" code that might find could have been done to try to speed things up or cut down on memory usage. It could also just be bad coding.

I think for the most part you try to make the code as readable as possible. Yes, you should care about performance but you need to understand where you can make gains, and where you just don't worry about it.
[/opinion]

theTroll


This throws up a question that's been on the back of my mind for some time. For example, in Accelerated C++ (a very fine book or so I'm told by many sources) the code always seemed to be somewhat dense. There would be a line of code where several things seemd to be going on at once and you would start in the innermost set of brackets & work out what was going on. Then to the next outer set of brackets with your worked out code & figure out what was going on & so on & so on. It could get confusing working out what was going on with that single line. But my questions are:

1. Is this an example of 'elegant' code and is something for a newbie like me to aim for?

2. With modern computers and modern languages/compliers like C#, is this writing of dense code still as important? Would it be easier - no - better, to spread that code over a number of lines to make it more readable, especially as programs seem to be getting more complex and handled by more programmers?

I realise that this may be a matter of opinion, but opinions from experienced programmers is just one thing this workshop really excels at.
TheTroll
TheTroll
Dense code is not necessarily efficient code. The reason people that is to have less typing, not to make the code more efficient. The complier "should" end up make the code about the same.

So instead of making dense code you should strive for readable code. Anyone should be able to look at your code and figure out what is going on.

theTroll
SamLowry
SamLowry
Quote:
Original post by simesf
Quote:
Original post by TheTroll
[opinion]
Back in the "old" days we did a lot of optimization for memory and processing because both were limited. Now days, with the current processors and memory it is
not as big as issue.

So some of the "convoluted" code that might find could have been done to try to speed things up or cut down on memory usage. It could also just be bad coding.

I think for the most part you try to make the code as readable as possible. Yes, you should care about performance but you need to understand where you can make gains, and where you just don't worry about it.
[/opinion]

theTroll


This throws up a question that's been on the back of my mind for some time. For example, in Accelerated C++ (a very fine book or so I'm told by many sources) the code always seemed to be somewhat dense. There would be a line of code where several things seemd to be going on at once and you would start in the innermost set of brackets & work out what was going on. Then to the next outer set of brackets with your worked out code & figure out what was going on & so on & so on. It could get confusing working out what was going on with that single line. But my questions are:

1. Is this an example of 'elegant' code and is something for a newbie like me to aim for?

2. With modern computers and modern languages/compliers like C#, is this writing of dense code still as important? Would it be easier - no - better, to spread that code over a number of lines to make it more readable, especially as programs seem to be getting more complex and handled by more programmers?

I realise that this may be a matter of opinion, but opinions from experienced programmers is just one thing this workshop really excels at.


[opinion from a not-so-experienced-programmer]
Personally, I hate it when people try to put everything on one line. It makes the entire thing a lot harder to read. Using temporary variables a) have names providing some description of the in-between values and b) it can make debugging a lot easier, especially if you're working with side effects (i.e. every time you evaluate a subexpression, it gives you a different result because state is an implicit parameter).

Also, "concise" code can depend on some little rules few people really know about, e.g. in C++ the order of evaluation of terms of a sum ( + ) is not defined. I believe it is in C#, but before you start down writing things like a++ + ++a, you should know that that expression does depend on the evaluation order, and that people should know exactly what guarantees the language makes about this. It is my opinion that a programmer should avoid relying on such details and make the code as "unambiguous" as possible.

Regarding efficiency, why does this keep popping up? I shouldn't even be answering this question, as this would clearly be a premature micro-optimisation. Doubly evil. But just because it's you: no it does not have any impact on efficiency. Compilers are pretty smart these days.
[/opinion]
SixPack00
SixPack00
Quote:
Original post by simesf
This throws up a question that's been on the back of my mind for some time. For example, in Accelerated C++ (a very fine book or so I'm told by many sources) the code always seemed to be somewhat dense. There would be a line of code where several things seemd to be going on at once and you would start in the innermost set of brackets & work out what was going on. Then to the next outer set of brackets with your worked out code & figure out what was going on & so on & so on. It could get confusing working out what was going on with that single line. But my questions are:

1. Is this an example of 'elegant' code and is something for a newbie like me to aim for?

2. With modern computers and modern languages/compliers like C#, is this writing of dense code still as important? Would it be easier - no - better, to spread that code over a number of lines to make it more readable, especially as programs seem to be getting more complex and handled by more programmers?

I realise that this may be a matter of opinion, but opinions from experienced programmers is just one thing this workshop really excels at.


[opinion]
I've been working in Programming and Database Administration since 1988. I've seen lots of compact code and I've seen simple code. In most cases, the code is optimized by the compiler. So what you're really dealing with is readability by the programmers.

Some people think that writing short, complex programming is job security. Maybe back in the days of Assembly that was OK, but not now. It's no longer one person working on a project. It's a team and if you can't work well within a team structure, you're out no matter how good you think your code is.
Telastyn
Telastyn
[opinion]
Quote:
Original post by simesf
1. Is this an example of 'elegant' code and is something for a newbie like me to aim for?


No. A raw newbie should aim for something that functions correctly. Then for readability (ease with which others can understand code). Then for maintainability (flexibility of design). Then for speed.

Quote:

2. With modern computers and modern languages/compliers like C#, is this writing of dense code still as important?


No. Arguably it wasn't then either.



And to a degree, it's not a matter of opinion, it's a matter of environment. In a business environment this is even more visible. (For this team/product/userbase) Is the developer time spent optimizing something to be faster going to produce more sales (money) then the developer's salary? (For this team/product/userbase) Is the loss of sales going to be more costly than the maintenance nightmare if a certain feature is implemented?

Often these are things which cannot be proven until after the fact or are too fickle or complex to determine. Generally though, programmer time is more costly than computing time and debugging speed is far slower than implementation speed. Thus helping debugging/maintenance saves you the most money/time/effort. Generally.
Spoonbender
Spoonbender
Quote:
Original post by simesf
2. With modern computers and modern languages/compliers like C#, is this writing of dense code still as important? Would it be easier - no - better, to spread that code over a number of lines to make it more readable, especially as programs seem to be getting more complex and handled by more programmers?

Writing dense code was never important. It's pretty much always better to go for readability.

Quote:
Original post by SamLowry
Personally, I hate it when people try to put everything on one line. It makes the entire thing a lot harder to read. Using temporary variables a) have names providing some description of the in-between values and b) it can make debugging a lot easier, especially if you're working with side effects (i.e. every time you evaluate a subexpression, it gives you a different result because state is an implicit parameter).

Agreed. Another important point here is that using temporaries is not inefficient. Beginners often assume that there's some overhead associated with creating variables. There isn't. And one of the first thing an optimizing compiler does anyway, is to split *everything* out into temporary variables. So if you do that yourself, you're both making more readable code, and making the compiler's job easier.

The same goes for reusing variables. Only do that when it makes the code easier to read (which isn't all that often)
Most of the time, it's easier to read if you just create new variables to hold new values. And the nice thing is, it is no less efficient. And it might just be *more* efficient in some cases.

And of course, despite all this, you shouldn't really care about efficiency to this degree. Go for readability first, and only if the code then turns out to be too slow, should you try to optimize.

But it's still worth pointing out that writing clean, readable code does not carry a performance overhead.

[Edited by - Spoonbender on July 27, 2007 9:11:30 PM]
simesf
simesf
Well that's a whole bunch of answers that made me a whole bunch happier. Thanks to all.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.