Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Use of the break; and continue; statments

202 views
Skip to first unread message

Bob Langelaan

unread,
May 18, 2017, 12:06:55 AM5/18/17
to
I teach a beginner C++ course and have taught my students that they should minimize the use of the break; and continue; statements. Recently I have been getting push back from some of my students with statements like "my friends at Microsoft tell me they use break; statements all the time" and similar types of objections.

I created the post below for my students on this topic some time ago. I would be interested in getting feedback on my post and the topic in general.

Thanks in advance,

Bob

===============================================================================

Many beginner programmers will unfortunately use the break statement and the continue statement a great deal more than they should.

I will go further and say that, generally speaking, a programmer should try to limit the use of break statements to exiting from a switch statement. And that the continue statement should almost never be used.

Here are examples of using the break statement and continue statement that should normally be avoided:

// An example of poor use of the break statement

while (exit_criteria not met)
{
.
.
.
if (exit_criteria_met)
{
break; // exit while loop immediately
}
.
.
.
} // end of while loop



// An example of poor use of the continue statement

while (exit_criteria not met)
{
.
.
.
if (exit_criteria_met)
{
continue; // Go immediately to the end of the while loop.
// Loop will exit with next iteration because
// the exit_criteria has been met.
}
.
.
.
} // end of while loop


In the 2 examples above, the exit_criteria is tested twice for each iteration of the while loop. This is considered both inefficient and poor programming style.

The following example is also considered poor programming style because you should be exiting a loop at the beginning of the loop or at the end of the loop, and not in the middle of the loop:

// Another example of poor use of the break statement

while (true) // The same as “while (1)” , but I prefer the former
{
.
.
.
if (exit_criteria_met)
{
break; // exit while loop
}
.
.
.
} // end of while loop



Using as an example a portion of the solution to exercise 4.13 of the text, here is how you can avoid the 3 poor examples above:

// prompt the user for the first value for miles

cout << "Enter the miles used (-1 to quit): ";

cin >> miles;



// Exit the loop if the input is -1, otherwise proceed with

// the next iteration of the loop.

while ( miles != -1 )

{

// prompt user for gallons and obtain the input from user

cout << "Enter gallons: ";

cin >> gallons;



.
. // Complete calculations using current values

. // input for miles and gallons



// prompt user for next value for miles

cout << "\n\nEnter the miles used (-1 to quit): ";

cin >> miles;

} // end while





The example above is a pattern that is used very commonly in well crafted code. You will note that it contains _NO_ break statements or continue statements, that there is only one test to exit the loop, and that this one test is done at the beginning of the loop.



Some of you will notice the solution above requires some code duplication. The code that inputs the miles is duplicated - once before entering the while loop and again at the end of the while loop. While we generally try to avoid code duplication, in this case, this code duplication is preferred over having an unnecessary break statement or continue statement in the loop. In other words, in this case it is considered the lessor of two evils :)



I will occasionally use a break statement in a situation similar to the next example:



// In the example below we are searching for a value in an array



bool found = false;

for (unsigned int value ; I < ARRAY_SIZE; ++i)// iterate through the array
{

if (myArray[i] == search_value)

{

found = true;

break; // exit loop since we have found search_value

}

}

// When we reach this point, “found” will be true if search_value was
// found in the array and false otherwise.

I tutor students from schools all over the lower mainland on C/C++. Several of these students have told me in the past that their instructors do not allow _ANY_ use of break statements, other than in a switch statement. So how would you rewrite the previous example without using a break statement, but still be equally efficient? Quite simply actually:



bool found = false;

// iterate through the array
for (unsigned int value ; (!found) && (i < ARRAY_SIZE); ++i)
{

if (myArray[i] == search_value)

{

found = true;

}

}



// When we reach this point, “found” will be true if search_value was found

// in the array and false otherwise.

Alf P. Steinbach

unread,
May 18, 2017, 1:27:43 AM5/18/17
to
On 18-May-17 6:06 AM, Bob Langelaan wrote:
> I teach a beginner C++ course and have taught my students that they
> should minimize the use of the break; and continue; statements.

Good advice. :)


> Recently I have been getting push back from some of my students with
> statements like "my friends at Microsoft tell me they use break;
> statements all the time" and similar types of objections.
>
> I created the post below for my students on this topic some time ago.
> I would be interested in getting feedback on my post and the topic in
> general.

Well, the concrete advice on rewriting a loop-and-a-half,

for( ;; )
{
int value;
cout << "Value (0 to quit? ";
cin >> value;
if( value == 0 )
{
break;
}
// Do computations, present result.
}

as

int value;
cout << "Value (0 to quit? ";
cin >> value;
while( value != 0 )
{
// Do computations, present result.
cout << "Value (0 to quit? ";
cin >> value;
}

is ungood, downright evil, because

1. it introduces undesirable redundancy, repeated code. Not doing that
is known as the DRY principle: Don't Repeat Yourself. Stick to DRY.

2. It needlessly expands the scope of the support variables.
And if that scope is contained via an outer curly braces block,
then it needlessly adds extra indentation.

You say about it:

> Some of you will notice the solution above requires some code
> duplication. The code that inputs the miles is duplicated - once before
> entering the while loop and again at the end of the while loop. While we
> generally try to avoid code duplication, in this case, this code
> duplication is preferred over having an unnecessary break statement or
> continue statement in the loop. In other words, in this case it is
> considered the lessor of two evils :)

No, it's not the lesser of two evils. It's an evil introduced to avoid
perfectly good ordinary code because you have OVER-GENERALIZED a rule
about avoiding `break`. You have made it an absolute rule, which is easy
to follow mechanically but produces rather sub-optimal results, instead
of a guideline that requires intelligence in its application.

Instead IMO you should teach your students about loop-and-a-half: how to
recognize that it's logically there (code duplication) and how to
express it properly (with a break or return or throw in the middle).

• • •

That said, your students' argument about `break` being used at Microsoft
is not a valid argument.

Very seldom do you find as dirty and invalid code as at Microsoft. To
wit, their documentation has a host of instances of invalid `void main`.
Not to mention the Microsoft monstrosities such as `tmain`. These are
beginner mistakes. And they're all over the place at MS.


Cheers & hth.,

- Alf

Christian Gollwitzer

unread,
May 18, 2017, 2:13:10 AM5/18/17
to
Am 18.05.17 um 07:27 schrieb Alf P. Steinbach:
> On 18-May-17 6:06 AM, Bob Langelaan wrote:
>> Some of you will notice the solution above requires some code
>> duplication. The code that inputs the miles is duplicated - once before
>> entering the while loop and again at the end of the while loop. While we
>> generally try to avoid code duplication, in this case, this code
>> duplication is preferred over having an unnecessary break statement or
>> continue statement in the loop. In other words, in this case it is
>> considered the lessor of two evils :)
>
> No, it's not the lesser of two evils. It's an evil introduced to avoid
> perfectly good ordinary code because you have OVER-GENERALIZED a rule
> about avoiding `break`.

+1.

Upon reading this paragraph, I thought it to be satirical, but from the
following it appears that you mean it as written. It is neither good to
repeat the loop condition, nor to repeat the code, but repeating more
than one line of code as a trade-in for not repeating the loop condition
nor using break sounds absurd.

Break is there for a reason. The alternative would be to set a condition
flag, not to repeat the code. I prefer break over condition flags if it
can be clearly expressed that way.

Christian

Christian Gollwitzer

unread,
May 18, 2017, 2:14:34 AM5/18/17
to
Am 18.05.17 um 08:13 schrieb Christian Gollwitzer:
> Am 18.05.17 um 07:27 schrieb Alf P. Steinbach:
>> On 18-May-17 6:06 AM, Bob Langelaan wrote:
>>> Some of you will notice the solution above requires some code
>>> duplication. The code that inputs the miles is duplicated - once before
>>> entering the while loop and again at the end of the while loop. While we
>>> generally try to avoid code duplication, in this case, this code
>>> duplication is preferred over having an unnecessary break statement or
>>> continue statement in the loop. In other words, in this case it is
>>> considered the lessor of two evils :)
>>
>> No, it's not the lesser of two evils. It's an evil introduced to avoid
>> perfectly good ordinary code because you have OVER-GENERALIZED a rule
>> about avoiding `break`.
>
> +1.
>
> Upon reading this paragraph, I thought it to be satirical,

I meant the OP's paragraph, just to make that clear ;)

Christian

bitrex

unread,
May 18, 2017, 2:30:11 AM5/18/17
to
On 05/18/2017 12:06 AM, Bob Langelaan wrote:

> bool found = false;
>
> // iterate through the array
> for (unsigned int value ; (!found) && (i < ARRAY_SIZE); ++i)
> {
>
> if (myArray[i] == search_value)
>
> {
>
> found = true;
>
> }
>
> }

bool found = false;

for (size_t i = 0; i < ARRAY_SIZE; ++i)
{
if (!found) { found = (myArray[i] == search_value); } else break;
}

Break statements are cool

Ian Collins

unread,
May 18, 2017, 2:34:35 AM5/18/17
to
On 05/18/17 04:06 PM, Bob Langelaan wrote:
> I teach a beginner C++ course and have taught my students that they
> should minimize the use of the break; and continue; statements.

Good advice with an emphasis on "minimise", they sometimes have their place.

Most places where beak is used in a loop can be replaced with a return
if the loop is extracted into a function :)

--
Ian

David Brown

unread,
May 18, 2017, 3:37:02 AM5/18/17
to
(/Please/ get a proper newsreader. It is nearly impossible to deal with
google-groups line split crap without making a mess.)

On 18/05/17 06:06, Bob Langelaan wrote:
> I teach a beginner C++ course and have taught my students that they
> should minimize the use of the break; and continue; statements. Recently
> I have been getting push back from some of my students with statements
> like "my friends at Microsoft tell me they use break; statements all the
> time" and similar types of objections.
>

/Minimizing/ the use of "break" is good - obsessing about it or banning
it is not. I find "continue" to be very rarely useful - I could happily
live without it in the language. But sometimes "break" really is the
best way to structure a loop.

> I created the post below for my students on this topic some time
> ago.
> I would be interested in getting feedback on my post and the topic in
> general.
>
> Thanks in advance,>
> Bob
>
> ===============================================================================
>
> Many beginner programmers will unfortunately use the break statement
> and the continue statement a great deal more than they should.
>
> I will go further and say that, generally speaking, a programmer
> should try to limit the use of break statements to exiting from a switch
> statement. And that the continue statement should almost never be used.
>

That paragraph does not read well. I first thought you had said that
"break" should not be used to exit switch statements either.

> Here are examples of using the break statement and continue
> statement
> that should normally be avoided:
>
> // An example of poor use of the break statement
>
> while (exit_criteria not met)
> {
> .
> .
> .
> if (exit_criteria_met)
> {
> break; // exit while loop immediately
> }
> .
> .
> .
> } // end of while loop
>

It is rare that you want to have the same test twice - but not /always/
bad. It is likely that in a case like this, you could remove the
condition at the start, making it a "while (true)" loop. In a "while
(true)" loop, it is perfectly clear that the loop exit will be done
somewhere in the middle of the loop (except for intentionally
never-ending loops).

>
>
> // An example of poor use of the continue statement
>
> while (exit_criteria not met)
> {
> .
> .
> .
> if (exit_criteria_met)
> {
> continue; // Go immediately to the end of the while loop.
> // Loop will exit with next iteration because
> // the exit_criteria has been met.
> }
> .
> .
> .
> } // end of while loop

"Continue" here is daft - it should be "break".

>
>
> In the 2 examples above, the exit_criteria is tested twice for each
> iteration of the while loop. This is considered both inefficient and
> poor programming style.

Don't claim that something "is considered" unless you can back it up
with clear justifications. Provide references from the Google C++ style
guide, or MISRA, or quotations from one of the C++ "greats". If you
cannot, then be honest and write "I consider it...".

And I don't think you can really claim it is inefficient, if the test
condition does not require external calls - the compiler will probably
be able to optimise that "continue" into a single jump to outside the
loop, just like a "break".

>
> The following example is also considered poor programming style
> because you should be exiting a loop at the beginning of the loop or at
> the end of the loop, and not in the middle of the loop:
>

Who says? /Why/ do you think that is a good idea?

This all comes across as very dogmatic to me. It looks like you want to
avoid exits in the middle of a loop simply because that is a rule that
/you/ were taught.

It is fine to say that exits in the middle of a loop are often hard to
follow, and make the flow of the code unclear. That is a /reason/ for
minimising the use of "break" and "continue". Saying they should be
avoided because it is "considered poor programming style" is not a
reason - any more than saying that "friends at Microsoft use break" is a
good reason to use them.

> // Another example of poor use of the break statement
>
> while (true) // The same as “while (1)” , but I prefer the former

(Side issue - I agree that "while (true)" is the nicest way to write
such loops. I dislike the use of "1" for a boolean, and I think the
alternative "for (;;)" is ugly. But beauty is in the eye of the beholder.)

> {
> .
> .
> .
> if (exit_criteria_met)
> {
> break; // exit while loop
> }
> .
> .
> .
> } // end of while loop
>

Often that is a perfectly good way to structure a loop. When you see
"while (true)" at the start of a loop, you are in no doubt that the exit
condition comes in the middle of the loop somewhere. If you don't know
that it is time to exit until the middle of the loop, then putting a
"break" (or perhaps "return") there seems perfectly reasonable.

Another situation where the use of "while (true)" and breaks can make
sense is if the exit criteria is complex. It may be natural to put
these at the beginning or the end of the loop, but it can be clearer to
have multiple statements, with space for comments, rather than jamming
everything into one exit expression. (There are, of course, alternative
restructurings - such as re-factoring the conditions into a function.)

So rather than:

while (A && B && !C) {
...
}

consider:

while (true) {
if (!A) break; // Exit if A does not hold
if (!B) break; // Exit if B does not hold
if (C) break; // Exit when C is reached
...
Sometimes code duplication is unavoidable. In such cases, choose to
duplicate the simplest, shortest, clearest code - not the major lines.
Testing "(miles == -1)" is far simpler and "smaller" than "cin >>
miles". Thus it is the test that should be duplicated, /not/ the action
of reading cin.

So while I agree that you may need to choose the lesser of two evils, I
think you have got the answer completely wrong in this case.

The best structuring here is very simple:

while (true) {
cout << "Enter the miles used (-1 to quit): ";
cin >> miles;
if (miles == -1) break;
...
}

Then there is /no/ duplication of either the important statements, or
the test.


>
>
> I will occasionally use a break statement in a situation similar to
> the next example:
>
>
>
> // In the example below we are searching for a value in an array
>
>
>
> bool found = false;
>
> for (unsigned int value ; I < ARRAY_SIZE; ++i)// iterate through the array
> {
>
> if (myArray[i] == search_value)
>
> {
>
> found = true;
>
> break; // exit loop since we have found search_value
>
> }
>
> }
>
> // When we reach this point, “found” will be true if search_value was
> // found in the array and false otherwise.
>

Baring typos in the code (which are a /really/ bad idea in a post to
students!), that is a perfectly good use of "break".

> I tutor students from schools all over the lower mainland on C/C++.
> Several of these students have told me in the past that their
> instructors do not allow _ANY_ use of break statements, other than in a
> switch statement. So how would you rewrite the previous example without
> using a break statement, but still be equally efficient? Quite simply
> actually:
>

The world is a big place, and this is an international newsgroup - no
one can guess where "the lower mainland" is.

I am always wary of hard and fast rules such as /never/ using break
statements. I need justification - the stronger the rule, the more
justification I need.

And efficiency should not be your major concern here - code clarity and
correctness trump efficiency every time. If you are going to have a
rule about code style, ask yourself:

Does it make it easier to write correct code?
Does it make it harder to write incorrect code?
Does it make it easier to see that correct code is correct?
Does it make it easier to see that incorrect code is incorrect?

For the most part, pick efficient algorithms and let the compiler worry
about the efficiency of the detail in the code. The compiler is not
going to follow your structure of loops and breaks anyway.

>
>
> bool found = false;
>
> // iterate through the array
> for (unsigned int value ; (!found) && (i < ARRAY_SIZE); ++i)
> {
>
> if (myArray[i] == search_value)
>
> {
>
> found = true;
>
> }
>
> }
>

In my book, the complex condition in the for loop makes it poor code -
it is unclear. It is not as bad as using "i = ARRAY_SIZE" to jump to
the end of the loop, but it is still bad. This kind of exercise is a
very artificial problem, and there are no nice answers. They can be
useful while learning, but that does not make them good style in practice.

Fred.Zwarts

unread,
May 18, 2017, 4:00:29 AM5/18/17
to
"bitrex" schreef in bericht news:KbbTA.89595$rl4....@fx35.iad...
>
>On 05/18/2017 12:06 AM, Bob Langelaan wrote:
>
>> bool found = false;
>>
>> // iterate through the array
>> for (unsigned int value ; (!found) && (i < ARRAY_SIZE); ++i)
>> {
>>
>> if (myArray[i] == search_value)
>>
>
>bool found = false;
>
>for (size_t i = 0; i < ARRAY_SIZE; ++i)
>{
> if (!found) { found = (myArray[i] == search_value); } else break;
>}
>
>Break statements are cool

Matter of taste. I would write:

bool found = false;
for (size_t i = 0; i < ARRAY_SIZE && !found; ++i) {

Cholo Lennon

unread,
May 18, 2017, 9:07:22 AM5/18/17
to
On 18/05/17 08:53, Stefan Ram wrote:
> Bob Langelaan <bobl...@gmail.com> writes:
>> cout << "Enter the miles used (-1 to quit): ";
>> cin >> miles;
>> while ( miles != -1 )
>> {
>> cout << "\n\nEnter the miles used (-1 to quit): ";
>> cin >> miles;
>> }
>
> My course participants have learned function definitions
> /before/ control structures. So they could avoid the
> definition using:
>
> #include <initializer_list>
> #include <iostream>
> #include <ostream>
> #include <string>
>
> using namespace ::std::literals;
>
> int read_miles()
> { int miles {};
> ::std::cout << "Enter the miles used (-1 to quit): "s;

Why the use of the literal s? It's really unnecessary :-O


> ::std::cin >> miles;
> return miles; }
>
> int main()
> { int miles {};
> while(( miles = read_miles() )!= -1 )
> { /* ... */ }}
>
> However, I deem the whole field of input too difficult for
> my beginner's course and only treat it later in the advanced
> course.
>
> I usually do not mention »break;« at all and so I never saw
> it in the program of a participant IIRC. However, I do not
> avoid »break;« because I thing that ignorance will lead to
> a better programming style, but only because my beginner's
> course usually is too short and the advanced course has a
> different scope (user-defined types).
>


--
Cholo Lennon
Bs.As.
ARG

bitrex

unread,
May 18, 2017, 9:49:12 AM5/18/17
to
Years of Python has corrupted me I think. ;-)

I don't like having multiple conditionals in for loops, I think it can
be kinda confusing

bitrex

unread,
May 18, 2017, 9:54:00 AM5/18/17
to
Under gcc 7.1 x86 with -std=c++11 -O1 FWIW both our variations compile
to the same sequence of instructions.

bitrex

unread,
May 18, 2017, 10:08:38 AM5/18/17
to
On 05/18/2017 08:14 AM, Stefan Ram wrote:

> One reason, I give to my participants for SESE is
> that without SESE it can be much more difficult to
> apply an "extract method" refactor or to add something
> that should be done on every entry to or exit of a block.

If one's methods are so bloated that one can't pretty much immediately
see where the exit points are then they need to go on a diet...

bitrex

unread,
May 18, 2017, 10:18:11 AM5/18/17
to
Granted I'm a relative newcomer to C++; I never used the language "back
in the day", I mostly have experience with straight C99, Python, and a
little Lisp/Clojure.

I've been trying to go straight to learning "modern C++" i.e. how things
are done post C++11. I feel like big blocks of conditionals/if
statements/switch statements are old 90s shit like what I was writing in
C back then. I can't remember the last time I used a switch statement or
multiple layers of if/else blocks in something I've written in C++...it
feels too much like the "bad old days" and I figure I must be doing
something wrong.

Alf P. Steinbach

unread,
May 18, 2017, 10:20:17 AM5/18/17
to
On 18-May-17 9:36 AM, David Brown wrote:
[snip]
> Don't claim that something "is considered" unless you can back it up
> with clear justifications. Provide references from the Google C++ style
> guide, or MISRA, or quotations from one of the C++ "greats". If you
> cannot, then be honest and write "I consider it...".

Uhm, the Google C++ style guide is designed (if it is designed) for a C
style legacy code base.

It would not be a good idea to use it as an authority on anything C++.

Don't know about MISRA but I suspect the same story: a special purpose
thing.


Cheers!,

- Alf

David Brown

unread,
May 18, 2017, 11:03:17 AM5/18/17
to
My point is that you can't claim something "is considered bad style"
unless you can point to a reference. It is up the OP to find what he
feels is an appropriate reference for his claim.


David Brown

unread,
May 18, 2017, 11:06:48 AM5/18/17
to
On 18/05/17 15:07, Cholo Lennon wrote:
> On 18/05/17 08:53, Stefan Ram wrote:
>> Bob Langelaan <bobl...@gmail.com> writes:
>>> cout << "Enter the miles used (-1 to quit): ";
>>> cin >> miles;
>>> while ( miles != -1 )
>>> {
>>> cout << "\n\nEnter the miles used (-1 to quit): ";
>>> cin >> miles;
>>> }
>>
>> My course participants have learned function definitions
>> /before/ control structures. So they could avoid the
>> definition using:
>>
>> #include <initializer_list>
>> #include <iostream>
>> #include <ostream>
>> #include <string>
>>
>> using namespace ::std::literals;
>>
>> int read_miles()
>> { int miles {};
>> ::std::cout << "Enter the miles used (-1 to quit): "s;
>
> Why the use of the literal s? It's really unnecessary :-O

It is there for the same reason as the annoying extra ::, the ugly,
weird and unnecessary initialisation of variables like "int miles {};",
and the strange bracketing style.

I suspect the point is that he can tell if his students wrote their
homework code themselves rather than copying and pasting it from the
internet - by encouraging this unique style that is different from
everyone else, students will be forced to re-write anything they copy.

Jorgen Grahn

unread,
May 18, 2017, 11:26:32 AM5/18/17
to
On Thu, 2017-05-18, Bob Langelaan wrote:
> I teach a beginner C++ course and have taught my students that they
> should minimize the use of the break; and continue;
> statements. Recently I have been getting push back from some of my
> students with statements like "my friends at Microsoft tell me they
> use break; statements all the time" and similar types of objections.
>
> I created the post below for my students on this topic some time
> ago. I would be interested in getting feedback on my post and the
> topic in general.

To add my five cents to the big pile: I think I'm guided by this:

- I want to be able to read my loops and convince myself they are
correct.
- My efforts may be better needed elsewhere.

Break, continue, return and throw sometimes helps with both those
things, so I use them.

What I'd do if I was you would be to teach the students to /read/ a
loop, so they can tell if it's correct or not. Things like
invariants. When is it safe to enter this loop? What's the state
when we exit? What's always true inside of it?

If you can reason about those things even with break and continue,
they are applied correctly, and not a problem.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Daniel

unread,
May 18, 2017, 11:30:12 AM5/18/17
to
On Thursday, May 18, 2017 at 3:37:02 AM UTC-4, David Brown wrote:
>
> consider:
>
> while (true) {
> if (!A) break; // Exit if A does not hold
> if (!B) break; // Exit if B does not hold
> if (C) break; // Exit when C is reached
> ...
> }
>

For a moment I thought you were introducing a goto label.

Daniel

bitrex

unread,
May 18, 2017, 12:02:05 PM5/18/17
to
On 05/18/2017 10:34 AM, Stefan Ram wrote:
> I agree that methods should be small. This I also tell my
> participants.
>
> As an example, here's the latest version of my eight-queens
> program. It also features loops containing return statements,
> which must be something the OP also should dislike. (For a
> top-down reading, one should start at »main«, which is at
> the bottom of the program.)

Ya, rather short methods. I'm working on a little graphics engine at the
moment using Allegro 5 and probably 80% of my methods are fewer than 5
lines. I've been a little more lax; sometimes there's no choice but to
have a bunch of lines cuz you have to declare a bunch of verticies and
the straight-C API syntax is a little unwieldy, but anything more than
20 lines or so, that can't be fit on approximately half a display in the
IDE, feels too big.

bitrex

unread,
May 18, 2017, 12:20:49 PM5/18/17
to
On 05/18/2017 12:06 AM, Bob Langelaan wrote:
> I teach a beginner C++ course and have taught my students that they should minimize the use of the break; and continue; statements. Recently I have been getting push back from some of my students with statements like "my friends at Microsoft tell me they use break; statements all the time" and similar types of objections.
>
> I created the post below for my students on this topic some time ago. I would be interested in getting feedback on my post and the topic in general.
>
> Thanks in advance,
>
> Bob

<snip>

The question I would have is: are you actually teaching C++, or are you
teaching "intro programming concepts"? From the examples given it
doesn't seem like you're actually teaching C++ as many of them don't
even seem like very good modern C, much less modern C++.

IMO C++ isn't a very good "intro to programming concepts/computer
science" language. My first "real" programming languages (other than
Basic on the Apple II) were Pascal and C, simply because in 1991 or
whenever that was kind of what was available. If I'd had other options
though I don't think I would've picked those.

I've heard some say things like "but if you don't learn a systems
language first you'll never understand things like strong typing,
pointers, dynamic memory allocation, etc." and I don't know. I don't
really buy it.

If it is indeed a C++ course for people who already have programming
experience, where exactly are they coming from? They have "friends at
Microsoft" and yet need to be taught how to use "while" loops and when
break and continue is appropriate and when it isn't? I would think that
a "intro to C++" course for students who already have programming
experience would spend like 2 days on the various reserved words/control
structures in the language and then jump right into real C++ concepts
like classes, inheritance, virtual methods, RAII, smart pointers/memory
management, etc.

Many other languages have "continue" and "break" and loops and similar
structures. What gives?

Frankly these days if I absolutely had to use a general purpose systems
language for an "programming concepts" language it would probably be
something like Rust or Go and not C++.

woodb...@gmail.com

unread,
May 18, 2017, 2:10:45 PM5/18/17
to
+1. I generally don't have a problem with these things either.


Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net

woodb...@gmail.com

unread,
May 18, 2017, 2:22:11 PM5/18/17
to
It seems like C++ keeps getting better with time, though.


Brian
Ebenezer Enterprises
http://webEbenezer.net

bitrex

unread,
May 18, 2017, 5:03:16 PM5/18/17
to
On 05/18/2017 02:21 PM, woodb...@gmail.com wrote:

>> Frankly these days if I absolutely had to use a general purpose systems
>> language for an "programming concepts" language it would probably be
>> something like Rust or Go and not C++.
>
> It seems like C++ keeps getting better with time, though.
>
>
> Brian
> Ebenezer Enterprises
> http://webEbenezer.net
>

It's taken me longer to get up to speed with C++1x than say Python for
sure. But compared to what I remember of my brief messing with it years
ago it does feel like an entirely new beast. The time I've spent on it
recently has been a pleasant combination of frustration and amazement. ;-)

JiiPee

unread,
May 18, 2017, 5:57:24 PM5/18/17
to
On 18/05/2017 15:34, Stefan Ram wrote:
> struct board_type : public ::std::vector< position_type >
> {


Is this a good idea to inherit from a std class? Because I heard /read
its better to do like:

struct board_type

{

::std::vector< position_type > m_board;

...
};

and use m_board to get access to vector.

Alf P. Steinbach

unread,
May 18, 2017, 6:03:12 PM5/18/17
to
Or he could have used private inheritance.


Cheers!,

- Alf

Richard

unread,
May 18, 2017, 8:52:23 PM5/18/17
to
[Please do not mail me a copy of your followup]

"Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
<ofjb5r$eov$1...@dont-email.me> thusly:

>Very seldom do you find as dirty and invalid code as at Microsoft. To
>wit, their documentation has a host of instances of invalid `void main`.
>Not to mention the Microsoft monstrosities such as `tmain`. These are
>beginner mistakes. And they're all over the place at MS.

If you change the above "invalid code as at Microsoft" to read
"invalid code as shown in Microsoft documentation and samples" then I
would agree with you.

Having met many MS engineers (mostly 3D graphics dudes), I know that
the code that they write is just fine.

The code appearing in samples and documentation is often written by
interns or contractors and doesn't represent the actual engineering
practices at MS, beyond some superficialities like identifier
conventions.

James McNellis (who works at MS) talks about this a little bit in his
CppCon talk on modernizing a legacy code base.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Richard

unread,
May 18, 2017, 8:53:50 PM5/18/17
to
[Please do not mail me a copy of your followup]

Bob Langelaan <bobl...@gmail.com> spake the secret code
<891423c3-4986-441a...@googlegroups.com> thusly:

>I teach a beginner C++ course and have taught my students that they
>should minimize the use of the break; and continue; statements.

Minimizing is fine. Avoiding as a rule is silly. Do you not teach
them Duff's Device?

Richard

unread,
May 18, 2017, 8:56:56 PM5/18/17
to
[Please do not mail me a copy of your followup]

"Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
<ofkace$jbf$1...@dont-email.me> thusly:
I don't consider either of those guides authorities on anything but
their own specific development circumstances. For instance, the
Google guide is the authority on C++ coding at google, but not for
much else. Even then, if you contribute to clang while at google, the
google style guide does not apply, it's the clang style guide that
applies :).

Still, it is useful to read these documents because it gives a set of
rules that these groups feel are useful.

If your team doesn't know what rules they should adopt, it's a good
starting point for discussion, but I wouldn't blindly follow them just
"because muh Google".

Cholo Lennon

unread,
May 18, 2017, 9:35:15 PM5/18/17
to
On 05/18/2017 12:06 PM, David Brown wrote:
> On 18/05/17 15:07, Cholo Lennon wrote:
>> On 18/05/17 08:53, Stefan Ram wrote:
>>> Bob Langelaan <bobl...@gmail.com> writes:
>>>> cout << "Enter the miles used (-1 to quit): ";
>>>> cin >> miles;
>>>> while ( miles != -1 )
>>>> {
>>>> cout << "\n\nEnter the miles used (-1 to quit): ";
>>>> cin >> miles;
>>>> }
>>>
>>> My course participants have learned function definitions
>>> /before/ control structures. So they could avoid the
>>> definition using:
>>>
>>> #include <initializer_list>
>>> #include <iostream>
>>> #include <ostream>
>>> #include <string>
>>>
>>> using namespace ::std::literals;
>>>
>>> int read_miles()
>>> { int miles {};
>>> ::std::cout << "Enter the miles used (-1 to quit): "s;
>>
>> Why the use of the literal s? It's really unnecessary :-O
>
> It is there for the same reason as the annoying extra ::, the ugly,
> weird and unnecessary initialisation of variables like "int miles {};",
> and the strange bracketing style.
>

I totally agree with you! In my 25 years with C++ I've never felt the
necessity to use ::std, indeed, I never found a namespace named "std"
other than the defined by the standard library. Stefan has this kind of
paranoia (TM): in 'comp.lang.java.programmer' for example he posts code
where standard Java types are prefixed with the package 'java.lang'
(java.lang.String, java.lang.Integer, etc). Nobody does that! it's not
necessary (there are some situations related to Java class loaders, but
IMO, they are just corner cases).

And finally, yes, his bracketing style is really weird, never seen :-O

> I suspect the point is that he can tell if his students wrote their
> homework code themselves rather than copying and pasting it from the
> internet - by encouraging this unique style that is different from
> everyone else, students will be forced to re-write anything they copy.
>

It's a good theory :-)

Gareth Owen

unread,
May 19, 2017, 1:44:39 AM5/19/17
to
legaliz...@mail.xmission.com (Richard) writes:

> [Please do not mail me a copy of your followup]
>
> Bob Langelaan <bobl...@gmail.com> spake the secret code
> <891423c3-4986-441a...@googlegroups.com> thusly:
>
>>I teach a beginner C++ course and have taught my students that they
>>should minimize the use of the break; and continue; statements.
>
> Minimizing is fine. Avoiding as a rule is silly. Do you not teach
> them Duff's Device?

Unless they're saying "Do not write opaque nonsense like this unless
you have measured and literally every cycle is critical", they
absolutely shouldn't be teaching Duff's Device.

It's like teaching Civil Engineering based on the Leaning Tower of Pisa.
If programmers thought more like engineers and less like close-up
magicians - desperate to impress with their sleight of hand - the
world's software would be in a lot better place.

Tim Rentsch

unread,
May 19, 2017, 7:04:39 PM5/19/17
to
Bob Langelaan <bobl...@gmail.com> writes:

> I teach a beginner C++ course and have taught my students that they
> should minimize the use of the break; and continue; statements.
> Recently I have been getting push back from some of my students with
> statements like "my friends at Microsoft tell me they use break;
> statements all the time" and similar types of objections.
>
> I created the post below for my students on this topic some time ago.
> I would be interested in getting feedback on my post and the topic in
> general.
>
> [...]

I have comments both on the topic and on how to present it. I'll
try to give the comments mostly in that order.

First, I echo the response given by Ian Collins. If a loop uses
break (appropriately) to exit the loop, the code often can, and
usually should, be recast so that the loop is in a subfunction,
and 'return' is used rather than 'break'. Generally 'return' to
exit a loop early is better than 'break'. What's more, the most
common case for early loop exit is a search that found something,
in which case 'return' provides not only the exit out of the loop
but also a way of transmitting the value (eg an index or an
address) of what was found.

Second, I echo the response given by Jorgen Grahn. Start by
teaching function composition (including invariants for loops,
etc), and there won't be as much need for rules about 'break' and
'continue', etc. When beginners overuse such statements, usually
that indicates a deeper problem related to how they write code to
begin with (which at the level of a single function I use the
term "function composition"). If their function composition
skills are good, they won't need to be told which break/continue
are okay and which ones should be revised away; if not, trying
to follow heuristic rules probably won't help them much.

Some general comments: I don't use break or continue very often,
but I don't go out of my way to avoid them either. Partly that's
because my code composition habits mostly automatically avoid
them early, so I don't worry if I find myself writing one. Of
course that may not be true for beginners, so how can we help
them with that? Rather than say "minimize the use of break and
continue", I suggest something like "whenever you find yourself
starting to write 'break' or 'continue', ask yourself if there's
a way to write the code that is easier to understand." The first
step is to be aware of cases that might need further exploration.

Having said that, let me partially retract it. The behaviors of
'break' and 'continue' are actually pretty dissimilar, despite
them being close cousins in terms of syntax. I think it's a
mistake to lump them together in terms of composition advice.
The easier one is 'continue', which is (for loops) roughly akin
to what an early return in a function does: it says, "we know
what to do in this case, what that is is simple and not the main
line, so we're just going to get it out of the way and be done
with it." Especially benign are cases where the continue is at
the top level of the loop body (so nothing has happened between a
non-nested test and the 'continue' statement). Because of that,
I recommend writing these cases in a distinctive way, without
braces or nesting, eg

if (c == '\n' ) continue;

The more that has happened (eg side effects) since the start of
the loop and the continue test, and/or the more deeply nested the
'continue' statement, the redder the flag in a code review. And
conversely for less deeply nested and less state change since the
current loop iteration started.

What considerations are important is different with 'break'. I
have the same redness heuristic with 'break' about nesting as I
do with 'continue', but apart from that I really don't think of
them as being in the same category. Two of the examples you gave
for 'break' (with a 'found' flag, and code duplication), ran
counter to what I expected. Rather than pontificate about minor
points of style, let me say something about giving examples.
I recommend:

Examples be detailed and specific rather than generic
and abstract;

As much as possible examples be taken from actual code
rather than hypothetical examples;

The set of examples first include good usage (ie, where
breaks does not appear);

For each example of bad usage, a revised form be shown
that avoids the bad usage; and,

The set of examples last include cases where 'break' is
used appropriately.

These recommendations likewise apply for 'continue'. If you're
feeling ambitious, the example sets could include examples that
are "on the fence", ie, where there are plusses and minuses to
each of the different approaches, which might allow talking about
making tradeoffs in composition choices.

Okay I will stop here. If you decide to revise your tutorial I'd
be interested to see the results.

Alf P. Steinbach

unread,
May 19, 2017, 8:41:55 PM5/19/17
to
On 20-May-17 1:04 AM, Tim Rentsch wrote:
> [snipped very much] Two of the examples you gave
> for 'break' (with a 'found' flag, and code duplication), ran
> counter to what I expected. [snipped very much]

I think this de-emphasis, this hiding away of those two concrete issues,
is wrong and wrong-headed. Concrete advice about concrete situations
affects the behavior the most, has the most impact. Abstract advice is
nice but needs to build on a concrete foundation of examples, even if it
maybe sounds more impressive.


Cheers!,

- Alf

Tim Rentsch

unread,
May 19, 2017, 8:59:25 PM5/19/17
to
I didn't (and still don't) consider them the high-order bits of
what I was saying. Also I thought it would be counter-productive
to get into a style debate, especially since I wasn't trying to
say that either approach was better, only that what he said isn't
what I would have expected.

You are welcome to re-write the comments in my posting to say
what I was saying in a way you think would be more effective.
If you do I look forward to reading it.

Alf P. Steinbach

unread,
May 19, 2017, 10:11:42 PM5/19/17
to
On 20-May-17 2:59 AM, Tim Rentsch wrote:
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>
>> On 20-May-17 1:04 AM, Tim Rentsch wrote:
>>> [snipped very much] Two of the examples you gave
>>> for 'break' (with a 'found' flag, and code duplication), ran
>>> counter to what I expected. [snipped very much]
>>
>> I think this de-emphasis, this hiding away of those two concrete
>> issues, is wrong and wrong-headed. Concrete advice about concrete
>> situations affects the behavior the most, has the most
>> impact. Abstract advice is nice but needs to build on a concrete
>> foundation of examples, even if it maybe sounds more impressive.
>
> I didn't (and still don't) consider them the high-order bits of
> what I was saying. Also I thought it would be counter-productive
> to get into a style debate, especially since I wasn't trying to
> say that either approach was better, only that what he said isn't
> what I would have expected.

So the ~5000 characters you wrote about abstract considerations of style
for loops (essentially, minimize use of break and continue), and that
there are other things to learn about in a general programming
curriculum, was not, in your opinion, about style issues.

But concrete examples showing how to duplicate code and add complication
such as success flag, on ideological grounds, are in your opinion “minor
points of style”.

IMO that's plain wrong, and it's a wrong-headed approach; sorry.

I'm not saying that style isn't important.

I'm saying that I think the de-emphasis is entirely wrong; that the
general approach of not actually addressing the concrete contents of the
OP's posting is wrong, even if it sounds nice; and also that the
apparent idea that all style issues are unimportant, is wrong.


> You are welcome to re-write the comments in my posting to say
> what I was saying in a way you think would be more effective.
> If you do I look forward to reading it.

I wouldn't write that as a response to the OP's posting.

A general discussion of how to teach programming would involve much more.

And I'm much less sure than you appear to be, about what /is/ a good
approach or weighting of issues. I have extensive experience teaching
programming and software development in general, in vocational school,
at college, and in Accenture (a large consulting firm). And as I learned
more about teaching and how understanding of programming develops in
people, I became less and less sure about what should be early topics
and what constituted advanced, later stuff.

I read what you wrote as promoting an early focus on functional
decomposition. That's nice, but it's just one aspect.

In the private sector I identified a need to focus and teach error
handling, in particular use of exceptions, up front, because just about
every consultant had incorrect ideas about it. They'd write ugly
try-catch-finallies in Java, one in every function, and the designs
would be complicated and full of redundancy. Some would complain if an
exception was allowed to just propagate instead of taking a detour
through a try-catch-finally in every stack frame.

I still believe that one main reason students fresh from college have to
relearn a lot about programming when they start working, is that at
university/college they learn a kind of idealized programming world, one
where nothing ever fails, hence only the simplest error handling.

At the time, the late 1990's and early 2000's, DBC (Design By Contract)
was very much in vogue and I thought that was a good idea. It would be
in line with your idea of functional decomposition as a main early
topic. For simple loops it's about loop invariants and variants; for
functional decomposition it's about preconditiom requirements and
postcondition guarantees (which is where it intersects with exceptions
and error handling); and for classes it's about class invariants. But
the problems adding DBC support to C++, that proposal just failed, while
e.g. Eiffel has working DBC support, showed that DBC was much less
practical, much less generally applicable, than I believed.

It's possible that systematic teaching experiments are needed, for the
way that I formulated /ad hoc/ impressions from my teaching experience,
seems inadequate: I still don't know clearly enough what's bad and
what's good.

Still I would warn against too strong an emphasis on functional
decomposition, especially top-down stepwise refinement, since that's
strongly tied to the waterfall development process, which is a sure way
to end up with low quality over budget and over time. Make the most
important decisions affecting the most, when you know the least. On the
third hand, /naming/ things can probably not be emphasized too much, and
functional decomposition, naming actions, is a special case of that.


Cheers!,

- Alf

Paavo Helde

unread,
May 21, 2017, 10:14:13 AM5/21/17
to
On 20.05.2017 13:38, Stefan Ram wrote:
> So, a C++ program that
> was carefully crafted by a master to handle all errors and
> release all resources correctly might look to a beginner as
> if the author did not care about theses topics at all.

It just does not look like so, but RAII and exceptions allow one to
write most of the code genuinely not caring about how errors are handled.

woodb...@gmail.com

unread,
May 21, 2017, 3:12:17 PM5/21/17
to
On 20.05.2017 13:38, Stefan Ram wrote:
> So, a C++ program that
> was carefully crafted by a master to handle all errors and
> release all resources correctly might look to a beginner as
> if the author did not care about theses topics at all.

First Leigh so eloquently reminded us to "Read the Bible" and now
Stefan seems to be referring to 1st Corinthians 3:10:

"According to G-d's grace that was given to me, I have laid a foundation
as a skilled master builder, and another builds on it. But each one must
be careful how he builds on it."

I guess we can expect more boppers -- biblically oriented programmers.

Christian Gollwitzer

unread,
May 21, 2017, 3:27:09 PM5/21/17
to
Am 21.05.17 um 21:12 schrieb woodb...@gmail.com:
> I guess we can expect more boppers -- biblically oriented programmers.
>

backward oriented programmers?

Christian

Juha Nieminen

unread,
May 22, 2017, 2:42:46 AM5/22/17
to
Bob Langelaan <bobl...@gmail.com> wrote:
> I teach a beginner C++ course and have taught my students that they
> should minimize the use of the break; and continue;
> statements. Recently I have been getting push back from some of my
> students with statements like "my friends at Microsoft tell me they
> use break; statements all the time" and similar types of objections.

Either programming practices at Microsoft are pretty lax, or they
are just making that up (which wouldn't actually surprise me).

Personally I don't find the use of 'break' or 'continue' to be
problematic, but I find myself *needing* to use them very
rarely. It's indeed quite rare the situation where they are the
most natural and handy solution.

Of course "rare" does not mean "they are never, ever the best
solution". Sometimes they are (although in my experience, and
for some reason, cases where 'continue' is the most natural
solution is much, much rarer than cases where 'break' is.)

The inner loop of calculating the mandelbrot set is the perfect
example of where 'break' is the most natural solution:

for(iter = 0; iter < maxIterations; ++iter)
{
const double zr2 = zr*zr, zi2 = zi*zi;
if(zr2 + zi2 > 4.0) break;
zi = 2.0*zr*zi + im;
zr = zr2 - zi2 + re;
}

The only other (and perhaps arguably better) solution would be to
use 'return' instead of 'break', but that's in essense no
different. In either case the loop is being exited from the middle,
rather than at its ending condition. It's hard to argue for a better
and more fluent solution.

Personally I detest in these cases artificially and forcefully
introducing some boolean value which is checked in the loop conditional
and set inside the loop. It feels unnatural, artificial, and forced.
It feels like a kludge trying to fix a non-existent problem, and that
is its major flaw.

Tim Rentsch

unread,
May 24, 2017, 4:37:34 PM5/24/17
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:

> On 20-May-17 2:59 AM, Tim Rentsch wrote:
>> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>>
>>> On 20-May-17 1:04 AM, Tim Rentsch wrote:
>>>> [snipped very much] Two of the examples you gave
>>>> for 'break' (with a 'found' flag, and code duplication), ran
>>>> counter to what I expected. [snipped very much]
>>>
>>> I think this de-emphasis, this hiding away of those two concrete
>>> issues, is wrong and wrong-headed. Concrete advice about concrete
>>> situations affects the behavior the most, has the most
>>> impact. Abstract advice is nice but needs to build on a concrete
>>> foundation of examples, even if it maybe sounds more impressive.
>>
>> I didn't (and still don't) consider them the high-order bits of
>> what I was saying. Also I thought it would be counter-productive
>> to get into a style debate, especially since I wasn't trying to
>> say that either approach was better, only that what he said isn't
>> what I would have expected.
>
> So the ~5000 characters you wrote about abstract considerations of
> style for loops (essentially, minimize use of break and continue), and
> that there are other things to learn about in a general programming
> curriculum, was not, in your opinion, about style issues.
>
> But concrete examples showing how to duplicate code and add
> complication such as success flag, on ideological grounds, are in your
> opinion ?minor points of style?.
>
> IMO that's plain wrong, and it's a wrong-headed approach; sorry.
>
> I'm not saying that style isn't important.
>
> I'm saying that I think the de-emphasis is entirely wrong; that the
> general approach of not actually addressing the concrete contents of
> the OP's posting is wrong, even if it sounds nice; and also that the
> apparent idea that all style issues are unimportant, is wrong.

I'm sorry you found it so objectionable. All I can say is I was
trying to respond to the questions asked, with greater emphasis
on what I believe are more important points (and less emphasis on
less important points, obviously). I realize other people may
have different opinions about that; I was giving my own
opinions.

I should add that it looks like we have a couple of crossed
wires. Let me see if I can help uncross them. (That continues
below...)

>> You are welcome to re-write the comments in my posting to say
>> what I was saying in a way you think would be more effective.
>> If you do I look forward to reading it.
>
> I wouldn't write that as a response to the OP's posting.
>
> A general discussion of how to teach programming would involve much more.
>
> And I'm much less sure than you appear to be, about what /is/ a good
> approach or weighting of issues. I have extensive experience teaching
> programming and software development in general, in vocational school,
> at college, and in Accenture (a large consulting firm). And as I
> learned more about teaching and how understanding of programming
> develops in people, I became less and less sure about what should be
> early topics and what constituted advanced, later stuff.
>
> I read what you wrote as promoting an early focus on functional
> decomposition. That's nice, but it's just one aspect.

There are two important terms here that I think we are using
differently. First, I didn't say functional decomposition, I
said function composition. Second, I think you are using the
word "style" in a much broader sense than I am. When I say style
(without any other qualification), I mean minor differences that
are, more or less immediately, obviously equivalent. Canonical
example: "infinite" loop, with the well-known choices

for(;;){ ... }

while(1){ ... }

The difference here is one of style. In contrast, sorting done
by a selection sort and sorting done by an insertion sort is not
a style choice but a design choice. Another example: dealing
with different cases in a loop - should we write

while( (c = getchar()) != EOF ){
...
if( c == '\n' ) continue;
...
}

or should we write

while( (c = getchar()) != EOF ){
...
if( c != '\n' ){
...
}
}

It seems fairly obvious that these two different ways of writing
this loop are equivalent, and therefore the difference is one of
style (and let me be very clear here, /as I use the term/ - I
understand other people may use it differently).

The question of whether a particular choice is a style choice or
a design choice is not always clear cut. Are the alternatives
"obviously" equivalent or not? There definitely is some gray in
there in some cases. Despite that I think the distinction is a
useful one, and between the two design choices are more important
than style choices. Not that style choices are unimportant, just
not as important as design choices.

Please bear in mind that (at least for the most part) I am giving
an answer in the context of writing a single function definition.
I use the term "function composition" to describe the activity,
or result, of composing a single function body. Sometimes that
will necessarily involve pushing off some responsibility to a
putative new subfunction, but anything about the subfunction -
besides perhaps its name and what arguments it is presumed to
accept - is outside of the context in which I am attempting to
respond about use of 'break' or 'continue'. Furthermore, when
it comes time to write the new subfunction(s), it may very well
be that we change our minds and redo some or all of the calling
functions; again though that is outside the scope of my answers
about 'break' and 'continue'.

> In the private sector I identified a need to focus and teach error
> handling, in particular use of exceptions, up front, because just
> about every consultant had incorrect ideas about it. They'd write ugly
> try-catch-finallies in Java, one in every function, and the designs
> would be complicated and full of redundancy. Some would complain if an
> exception was allowed to just propagate instead of taking a detour
> through a try-catch-finally in every stack frame.

Error handling is (IMO, in case that needs saying) a larger and
more difficult topic than what I have been addressing. I ignored
error handing in my comments about 'break', etc, not because I
think it's less important but because it's a much larger topic
than just writing a single function definition well. I look at
it this way: if someone can't compose a single, well-crafted
function body when they don't have to worry about error handling,
they certainly won't be able to compose well-crafted function
bodies when they /do/ have to worry about error handling. If it
seems like I am sure about my educational approach, I expect
that's because I made a deliberate choice to focus on one scale
of concerns, and ignore scales much larger or much smaller than
that. It isn't the weight of the different areas, but the size
of the domain that I feel I can address - given the various time
and resource constraints - that determines which aspects are
included and which (such as error handling) are not brought up.

Tim Rentsch

unread,
May 26, 2017, 11:42:55 AM5/26/17
to
Juha Nieminen <nos...@thanks.invalid> writes:

> Bob Langelaan <bobl...@gmail.com> wrote:
>> I teach a beginner C++ course and have taught my students that they
>> should minimize the use of the break; and continue;
>> statements. Recently I have been getting push back from some of my
>> students [...
> ...]
>
> Personally I don't find the use of 'break' or 'continue' to be
> problematic, but I find myself *needing* to use them very
> rarely. It's indeed quite rare the situation where they are the
> most natural and handy solution.

I agree in spirit here, but I think it's important to add
something. Not all uses of 'break' or 'continue' are created
equal: some are no big deal, others are just awful. Also my
criteria for acceptance are slightly different - not "best"
or "most natural" but something like "within some tolerance
range of other ways of writing the same loop". Very few
problems have answers that are optimal along all axes at once,
and different people have different weights for various
tradeoffs.


> Of course "rare" does not mean "they are never, ever the best
> solution". Sometimes they are (although in my experience, and
> for some reason, cases where 'continue' is the most natural
> solution is much, much rarer than cases where 'break' is.)

This last part surprised me. My own reaction to 'continue' is
more mild than it is to 'break'. I wouldn't expect to see a big
difference in how often each is used. So I took some statistics
to check that out. The source is about 18 million lines of .c
files, about 50 open source projects of various types. On
average 'break' appears about 0.20 times per loop, 'continue'
appears about 0.12 times per loop. Disclaimer: there is
definitely some noise in the date, which I estimate at between
one and five percent. (Use of 'break' for switch() statements
was counted separately, about 3.57 breaks/switch().) The
relative amounts of breaks versus continues depended a lot
on loop type (values rounded to tenths of a percent):

loop type % all loops % breaks avg % continues avg
for 75.6 17.1 12.6
while 23.9 26.9 9.4
do/while 0.5 24.6 3.8

I'm not offering any conclusions, I just thought the data
might be of interest.


> The inner loop of calculating the mandelbrot set is the perfect
> example of where 'break' is the most natural solution:
>
> for(iter = 0; iter < maxIterations; ++iter)
> {
> const double zr2 = zr*zr, zi2 = zi*zi;
> if(zr2 + zi2 > 4.0) break;
> zi = 2.0*zr*zi + im;
> zr = zr2 - zi2 + re;
> }
>
> The only other (and perhaps arguably better) solution would be to
> use 'return' instead of 'break', but that's in essense no
> different. In either case the loop is being exited from the middle,
> rather than at its ending condition. It's hard to argue for a better
> and more fluent solution.

A very interesting example! It occured to me that we could
easily write this loop differently, without using break, if zr2
and zi2 were declared outside the loop:

iter = -1;
while( ++iter < maxIterations && (zr2 = zr*zr) + (zi2 = zi*zi) <= 4.0 ){
zi = 2.0*zr*zi + im;
zr = zr2 - zi2 + re;
}

If while() allows declarations (does C17 have this now?), the
loop control could be written this way

while( const double zr2 = zr*zr, zi2 = zi*zi; ++iter < maxIterations && zr2+zi2 < 4 )

which gives a long line. A similar approach could be used with
for(), except zr2 and zi2 could not be 'const', and there is
the pesky problem of initializing 'iter'.

If we take a step back and look from a slightly higher altitude,
this could be seen as a problem in micro-optimization. Instead
of using separate real and imaginary parts, if we use a complex
and trust the compiler to find the common sub-expressions and
eliminate them, the loop is very easy (assuming norm2() is, eg, a
static inline that gives the square of the length):

for( i = 0; i < i_limit && norm2(z) <= 4; i++ ){
z = z*z + c;
}

I don't mean to argue that any of these different ways of writing
this loop is "best", or "better" than the others. Each has its
own plusses and minuses. But I think it's interesting how
decisions in different areas can affect whether 'break;' comes
into the picture.


> Personally I detest in these cases artificially and forcefully
> introducing some boolean value which is checked in the loop conditional
> and set inside the loop. It feels unnatural, artificial, and forced.
> It feels like a kludge trying to fix a non-existent problem, and that
> is its major flaw.

I'll vote for that. :)

asetof...@gmail.com

unread,
May 29, 2017, 6:32:41 PM5/29/17
to
Goto label
It is ok work well for me

the same break in a loop or continue
I have seen are ok too
0 new messages