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

Newfangled constructs

140 views
Skip to first unread message

Mr Flibble

unread,
Nov 18, 2015, 2:04:49 PM11/18/15
to
The newfangled ranged based for loops whilst dinky and useful do have an
irritating niggle: how to break out of nested loops?

We could write:

bool found = false;
for (auto& e1 : seq1)
{
for (auto& e2 : seq2)
{
if (e2 == 42)
{
found = true;
break;
}
}
if (found)
break;
}

This solution is plain is ugly.

We could try using the infamous goto keyword:

for (auto& e1 : seq1)
{
for (auto& e2 : seq2)
{
if (e2 == 42)
goto found;
}
}
found:

This solution is brittle from a maintenance point of view even if this
is about the only sane use-case for the goto keyword.

We could of course be slightly more traditional:

bool found = false;
for (auto i = seq1.begin(); !found && i != seq1.end(); ++i)
{
for (auto j = seq2.begin(); !found && j != seq2.end(); ++j)
{
if (*j == 42)
found = true;
}
}

But alas we are no longer using the range based for loop and have
introduced the extra level of iterator indirection; annoying.

We could perhaps change the language syntax and introduce an OPTIONAL
conditional expression:

bool found = false;
for (auto& e1 : seq1; !found)
{
for (auto& e2 : seq2; !found)
{
if (e2 == 42)
found = true;
}
}

But I am not convinced. What to do sausages? :/

/Flibble

Gareth Owen

unread,
Nov 18, 2015, 2:20:36 PM11/18/15
to
Mr Flibble <flibbleREM...@i42.co.uk> writes:

> We could perhaps change the language syntax and introduce an OPTIONAL
> conditional expression:
>
> bool found = false;
> for (auto& e1 : seq1; !found)
> {
> for (auto& e2 : seq2; !found)
> {
> if (e2 == 42)
> found = true;
> }
> }
>
> But I am not convinced. What to do sausages? :/

Share your distaste for the narrow applicability of range base loops.

How about:
for ((auto& e1 : seq1)
&& conditional_1
&& conditional_2)
{
}

I'd also like to do the following, to add to row-vectors say

for(auto& x: vec1, auto& y: vec2, auto& z = vec3){
z = x+y;
}

for simultaneous iteration - i.e. which expands to

for(_x = vec1.begin(), _y = vec2.begin(), _z = vec3.begin();
_x != vec1.end(), _y != vec2.end(), _z != vec3.end();
++_x, ++_y, ++_z)
{
*_z = *_x + *_y;
}

> /Flibble

Sausages

Paavo Helde

unread,
Nov 18, 2015, 2:27:31 PM11/18/15
to
Mr Flibble <flibbleREM...@i42.co.uk> wrote in
news:qcudncPSS5EmVtHL...@giganews.com:
The 'found' variable here is artificial and increases the complexity of
the program for no reason. I would use 'goto'.

Another option is to place the inner loop in a different function, but
this would also increase the complexity of the program unnecessarily if
the new function does not serve a clear standalone task.

Daniel

unread,
Nov 18, 2015, 2:30:07 PM11/18/15
to
On Wednesday, November 18, 2015 at 2:04:49 PM UTC-5, Mr Flibble wrote:
> The newfangled ranged based for loops whilst dinky and useful do have an
> irritating niggle: how to break out of nested loops?
>
> We could write:
>
> bool found = false;
> for (auto& e1 : seq1)
> {
> for (auto& e2 : seq2)
> {
> if (e2 == 42)
> {
> found = true;
> break;
> }
> }
> if (found)
> break;
> }
>
> This solution is plain is ugly.
>
How about an elegant juxtaposition of old and new?

jmp_buf env;
int val = setjmp(env);

if (val == 0)
{
for (auto& e1 : seq1)
{
for (auto& e2 : seq2)
{
if (e2 == 42)
{
longjmp(env,1);
}
}
}
}

Daniel

Mr Flibble

unread,
Nov 18, 2015, 2:32:56 PM11/18/15
to
On 18/11/2015 19:29, Daniel wrote:
>
> jmp_buf env;
> int val = setjmp(env);
>
> if (val == 0)
> {
> for (auto& e1 : seq1)
> {
> for (auto& e2 : seq2)
> {
> if (e2 == 42)
> {
> longjmp(env,1);
> }
> }
> }
> }

Not compatible with destructors AFAIK sausages.

/Flibble


Mr Flibble

unread,
Nov 18, 2015, 2:34:18 PM11/18/15
to
On 18/11/2015 19:20, Gareth Owen wrote:
>
> Share your distaste for the narrow applicability of range base loops.
>
> How about:
> for ((auto& e1 : seq1)
> && conditional_1
> && conditional_2)
> {
> }

Perhaps.

>
> I'd also like to do the following, to add to row-vectors say
>
> for(auto& x: vec1, auto& y: vec2, auto& z = vec3){
> z = x+y;
> }
>
> for simultaneous iteration - i.e. which expands to
>
> for(_x = vec1.begin(), _y = vec2.begin(), _z = vec3.begin();
> _x != vec1.end(), _y != vec2.end(), _z != vec3.end();
> ++_x, ++_y, ++_z)
> {
> *_z = *_x + *_y;
> }

That would be very nice indeed sausages.

/Flibble

Daniel

unread,
Nov 18, 2015, 2:53:42 PM11/18/15
to
On Wednesday, November 18, 2015 at 2:32:56 PM UTC-5, Mr Flibble wrote:
>
> Not compatible with destructors AFAIK sausages.
>
Sadly, no.

Daniel

Cholo Lennon

unread,
Nov 18, 2015, 3:25:02 PM11/18/15
to
I still prefer the goto solution, it's clearer and faster :-) (note
that Java for example, doesn't have goto, but it has "break label;" for
these cases)

Regards

--
Cholo Lennon
Bs.As.
ARG


Scott Lurndal

unread,
Nov 18, 2015, 4:03:02 PM11/18/15
to
Substitute 'throw' for longmp and wrap
the outer loop in a try/catch.

Alf P. Steinbach

unread,
Nov 18, 2015, 4:03:05 PM11/18/15
to
On 11/18/2015 8:04 PM, Mr Flibble wrote:
> The newfangled ranged based for loops whilst dinky and useful do have an
> irritating niggle: how to break out of nested loops?
>
> We could write:
>
> bool found = false;
> for (auto& e1 : seq1)
> {
> for (auto& e2 : seq2)
> {
> if (e2 == 42)
> {
> found = true;
> break;
> }
> }
> if (found)
> break;
> }
>
> This solution is plain is ugly.

Agreed.



> We could try using the infamous goto keyword:
>
> for (auto& e1 : seq1)
> {
> for (auto& e2 : seq2)
> {
> if (e2 == 42)
> goto found;
> }
> }
> found:
>
> This solution is brittle from a maintenance point of view even if this
> is about the only sane use-case for the goto keyword.

I have no qualms about the "goto" here. Every other construct for this
is just euphemistic code to avoid writing the "goto" in clear. IMHO.


> [snip]
> But I am not convinced. What to do sausages? :/

I'd just write the "goto".

It's the same way as e.g. the use of "#include": one is implementing a
higher level language construct manually.

But if the word offends, then you can do this:

bool const found = [&]() -> bool
{
for( auto& e1 : seq1 )
{
for( auto& e2 : seq2 )
{
if( e2 == 42 ) { return true; }
}
}
return false;
}();
// Use "found" here.

Well, OK, that wasn't so bad as I feared.


Cheers & hth.,

- Alf

Juha Nieminen

unread,
Nov 19, 2015, 4:16:36 AM11/19/15
to
Mr Flibble <flibbleREM...@i42.co.uk> wrote:
> The newfangled ranged based for loops whilst dinky and useful do have an
> irritating niggle: how to break out of nested loops?

You put it into its own function (and use a return).

There's a reason why modern programming design guidelines instruct to split
code into smaller logical functions.

--- news://freenews.netfront.net/ - complaints: ne...@netfront.net ---

seeplus

unread,
Nov 19, 2015, 5:48:17 AM11/19/15
to
On Thursday, November 19, 2015 at 6:04:49 AM UTC+11, Mr Flibble wrote:
>
> We could try using the infamous goto keyword:
>
> for (auto& e1 : seq1)
> {
> for (auto& e2 : seq2)
> {
> if (e2 == 42)
> goto found;
> }
> }
> found:

Does that goto version work if you are going to actually use "found"?
Doesn't it end up at "found" if it does find... but also when it gets hit
at the end of the main for loop .... and there is no way of knowing which
event happened.
By coincidence yesterday I had to write a complicated version of this
using medium newfangled (! not with goto!) and there seems to be no way of escaping having a BOOL in there.

Luca Risolia

unread,
Nov 19, 2015, 11:26:57 AM11/19/15
to
On 18/11/2015 20:04, Mr Flibble wrote:
> The newfangled ranged based for loops whilst dinky and useful do have an
> irritating niggle: how to break out of nested loops?

> We could perhaps change the language syntax and introduce an OPTIONAL
> conditional expression:
>
> bool found = false;
> for (auto& e1 : seq1; !found)
> {
> for (auto& e2 : seq2; !found)
> {
> if (e2 == 42)
> found = true;
> }
> }
>
> But I am not convinced. What to do sausages? :/

lambdas?

bool found = [&] {
for (auto& e1 : seq1)
{
for (auto& e2 : seq2)
{
if (e2 == 42)

red floyd

unread,
Nov 19, 2015, 12:59:43 PM11/19/15
to
Alternatively:

try
{
for (auto& e1 : seq1)
{
for (auto& e2)
{
if (e2 == 42)
throw 42;
}
}
}
catch (int)
{
}

I'd almost prefer the goto. IMHO, breaking out of nested loops is
the only legitimate use of goto.


Mr Flibble

unread,
Nov 19, 2015, 2:28:56 PM11/19/15
to
On 19/11/2015 09:16, Juha Nieminen wrote:
> Mr Flibble <flibbleREM...@i42.co.uk> wrote:
>> The newfangled ranged based for loops whilst dinky and useful do have an
>> irritating niggle: how to break out of nested loops?
>
> You put it into its own function (and use a return).
>
> There's a reason why modern programming design guidelines instruct to split
> code into smaller logical functions.

Unnecessary functional decomposition can often increase a program's
complexity and in this case it is only necessary due to a shortcoming in
the language's syntax sausages.

/Flibble

Gareth Owen

unread,
Nov 19, 2015, 5:35:03 PM11/19/15
to
Quite.

Very few would suggest that the inner loop of

for(int r=0; r < rows;++r){
for(int c=0; c < cols;++c){
total += frobincate(arr[r][c]);
}
}

be refactored into a subroutine due to it inordinate length.

It may be that the lack of a multi-level break means that such
refactoring is the least of several evils in Mr Flibble's premature-exit
use-case, but lets not pretend that's a good thing.[0]

Similarly, using a lambda is a nice trick, but it would be better if the
trick were not necessary.

Personally, I prefer both the goto, and the

class NonLocalExit {};

try {
...
if(found) throw NonLocalExit;
...
}
catch(const NonLocalExit& e) {}

idiom.

Ian Collins

unread,
Nov 19, 2015, 5:53:52 PM11/19/15
to
Gareth Owen wrote:
> Mr Flibble <flibbleREM...@i42.co.uk> writes:
>
>> On 19/11/2015 09:16, Juha Nieminen wrote:
>>> Mr Flibble <flibbleREM...@i42.co.uk> wrote:
>>>> The newfangled ranged based for loops whilst dinky and useful do have an
>>>> irritating niggle: how to break out of nested loops?
>>>
>>> You put it into its own function (and use a return).
>>>
>>> There's a reason why modern programming design guidelines instruct to split
>>> code into smaller logical functions.
>>
>> Unnecessary functional decomposition can often increase a program's
>> complexity and in this case it is only necessary due to a shortcoming
>> in the language's syntax sausages.
>
> Quite.
>
> Very few would suggest that the inner loop of
>
> for(int r=0; r < rows;++r){
> for(int c=0; c < cols;++c){
> total += frobincate(arr[r][c]);
> }
> }
>
> be refactored into a subroutine due to it inordinate length.

No, but that wasn't the original form, was it? The original code was
looking for something, which in my opinion makes it an ideal candidate
for an extract method refactoring.

> It may be that the lack of a multi-level break means that such
> refactoring is the least of several evils in Mr Flibble's premature-exit
> use-case, but lets not pretend that's a good thing.[0]

I think it is. What would be clearer in the code flow, a nested loop
with a clunky exit mechanism or a call to an appropriately named function?

Let the compiler sort out the exit strategy when it inlines the function!

> Similarly, using a lambda is a nice trick, but it would be better if the
> trick were not necessary.
>
> Personally, I prefer both the goto, and the
>
> class NonLocalExit {};
>
> try {
> ...
> if(found) throw NonLocalExit;
> ...
> }
> catch(const NonLocalExit& e) {}

That's a terrible abuse of exceptions!

--
Ian Collins

Öö Tiib

unread,
Nov 19, 2015, 8:56:29 PM11/19/15
to
On Friday, 20 November 2015 00:53:52 UTC+2, Ian Collins wrote:
> Gareth Owen wrote:
> > Personally, I prefer both the goto, and the
> >
> > class NonLocalExit {};
> >
> > try {
> > ...
> > if(found) throw NonLocalExit;
> > ...
> > }
> > catch(const NonLocalExit& e) {}
>
> That's a terrible abuse of exceptions!

+1 Misused exception (thrown and caught in same function) makes that
code to look like garbage.

Common case like "found" is clear example when *not* to use exceptions.
Exceptions are for rare cases (that sometimes happen) like "corrupted",
"too_full", "broken", "short_circuited", "timed_out", "unavailable",
"underpowered" etc. The operation can not continue and so it breaks
with exception thrown up stack. Typically it is caught far since there
are nothing to do than to stop the whole feature.

Exception is optimized to have close to no cost when it isn't thrown
for being rather expensive when it is thrown. If normal or common
condition is signaled with it then that can hurt performance in major
way.

Gareth Owen

unread,
Nov 20, 2015, 2:04:25 AM11/20/15
to
Ian Collins <ian-...@hotmail.com> writes:

>> It may be that the lack of a multi-level break means that such
>> refactoring is the least of several evils in Mr Flibble's premature-exit
>> use-case, but lets not pretend that's a good thing.[0]
>
> I think it is. What would be clearer in the code flow, a nested loop
> with a clunky exit mechanism or a call to an appropriately named
> function?

Well, that's exactly what I meant by "lesser of several evils".

I happily accept that a function call may well be better than a nested
loop with clunky exit mechanism, but it wouldn't necessarily be better
than a nested loop with a much cleaner (entirely hypothetical) exit
mechanism, with the exit condition stored in the loop construct.

> Let the compiler sort out the exit strategy when it inlines the function!
>
>> Similarly, using a lambda is a nice trick, but it would be better if the
>> trick were not necessary.
>>
>> Personally, I prefer both the goto, and the
>>
>> class NonLocalExit {};
>>
>> try {
>> ...
>> if(found) throw NonLocalExit;
>> ...
>> }
>> catch(const NonLocalExit& e) {}
>
> That's a terrible abuse of exceptions!

They're just another language feature, and one that expresses the
desired behaviour "jump out of the normal flow of control and resume at
the end of the loop". It's a goto for people with a fear of 'goto'.

Let the compiler sort out the exit strategy when it optimises the function!

Would you consider it an abuse of exceptions if the (found) condition
was something that almost never happened?

Wouter van Ooijen

unread,
Nov 20, 2015, 2:07:31 AM11/20/15
to
Op 20-Nov-15 om 2:56 AM schreef Öö Tiib:
> On Friday, 20 November 2015 00:53:52 UTC+2, Ian Collins wrote:
>> Gareth Owen wrote:
>>> Personally, I prefer both the goto, and the
>>>
>>> class NonLocalExit {};
>>>
>>> try {
>>> ...
>>> if(found) throw NonLocalExit;
>>> ...
>>> }
>>> catch(const NonLocalExit& e) {}
>>
>> That's a terrible abuse of exceptions!
>
> +1 Misused exception (thrown and caught in same function) makes that
> code to look like garbage.

Maybe to your eye, but not necesarily to mine.

> Common case like "found" is clear example when *not* to use exceptions.
> Exceptions are for rare cases (that sometimes happen) like "corrupted",
> "too_full", "broken", "short_circuited", "timed_out", "unavailable",
> "underpowered" etc. The operation can not continue and so it breaks
> with exception thrown up stack. Typically it is caught far since there
> are nothing to do than to stop the whole feature.

BTW how do you know for sure that (found) is a common case?

> Exception is optimized to have close to no cost when it isn't thrown
> for being rather expensive when it is thrown. If normal or common
> condition is signaled with it then that can hurt performance in major
> way.

Which makes your opinion of how exceptions should be used an example of
implementation-dependendt optimization. double yuk.

I can accept arguments based on readablity, but I abhor premature
optimization.

Wouter

Gareth Owen

unread,
Nov 20, 2015, 2:26:41 AM11/20/15
to
Wouter van Ooijen <wou...@voti.nl> writes:

>> +1 Misused exception (thrown and caught in same function) makes that
>> code to look like garbage.
>
> Maybe to your eye, but not necesarily to mine.
>
> BTW how do you know for sure that (found) is a common case?
>
> Which makes your opinion of how exceptions should be used an example
> of implementation-dependendt optimization. double yuk.
>
> I can accept arguments based on readablity, but I abhor premature
> optimization.

I agree with Wouter.

Ian Collins

unread,
Nov 20, 2015, 2:59:27 AM11/20/15
to
Gareth Owen wrote:
> Ian Collins <ian-...@hotmail.com> writes:
>
>>> It may be that the lack of a multi-level break means that such
>>> refactoring is the least of several evils in Mr Flibble's premature-exit
>>> use-case, but lets not pretend that's a good thing.[0]
>>
>> I think it is. What would be clearer in the code flow, a nested loop
>> with a clunky exit mechanism or a call to an appropriately named
>> function?
>
> Well, that's exactly what I meant by "lesser of several evils".
>
> I happily accept that a function call may well be better than a nested
> loop with clunky exit mechanism, but it wouldn't necessarily be better
> than a nested loop with a much cleaner (entirely hypothetical) exit
> mechanism, with the exit condition stored in the loop construct.

I would usually say it was.

>> Let the compiler sort out the exit strategy when it inlines the function!
>>
>>> Similarly, using a lambda is a nice trick, but it would be better if the
>>> trick were not necessary.
>>>
>>> Personally, I prefer both the goto, and the
>>>
>>> class NonLocalExit {};
>>>
>>> try {
>>> ...
>>> if(found) throw NonLocalExit;
>>> ...
>>> }
>>> catch(const NonLocalExit& e) {}
>>
>> That's a terrible abuse of exceptions!
>
> They're just another language feature, and one that expresses the
> desired behaviour "jump out of the normal flow of control and resume at
> the end of the loop". It's a goto for people with a fear of 'goto'.
>
> Let the compiler sort out the exit strategy when it optimises the function!
>
> Would you consider it an abuse of exceptions if the (found) condition
> was something that almost never happened?

Yes.

--
Ian Collins

David Brown

unread,
Nov 20, 2015, 3:08:08 AM11/20/15
to
If the compiler knows all about a particular exception, since it is
thrown and caught in the same function (and it can be sure that the
exception cannot escape), then it is perfectly free to optimise such
code into a "goto".

I am not saying that such a use of exceptions is a good idea in general,
merely that it is not necessarily as inefficient as you think.


Juha Nieminen

unread,
Nov 20, 2015, 5:23:42 AM11/20/15
to
red floyd <no....@its.invalid> wrote:
> I'd almost prefer the goto. IMHO, breaking out of nested loops is
> the only legitimate use of goto.

No, it isn't. "Goto considered harmful" is not just a light quip.
It's actually quite a useful principle.

The correct way is to put the loop in its own function, and use
'return' there.

If your code is such that doing so would be laborious and contrived,
then that's a sign that you need a redesign. Carefully redesign your
implementation in such a manner that putting the nested loop in its
own function becomes natural, clean, understandable and efficient,
and you will suddenly realize how much better your implementation
has become overall (ie. not just for this particular nested loop.)

Splitting larger functions into smaller ones, in a logical and
structured manner, improves the quality and usability of your code.
You don't need to go overboard with this, but once you start
having a function with more than, say 20 or 30 lines of code,
sit back and rethink what you are doing, and whether you could do
it better.

Doing it cleanly like that might positively surprise you later,
when refactoring and enhancing the code becomes easier.

Juha Nieminen

unread,
Nov 20, 2015, 5:29:39 AM11/20/15
to
Mr Flibble <flibbleREM...@i42.co.uk> wrote:
> Unnecessary functional decomposition can often increase a program's
> complexity

Citation needed.

It seems to me that this notion may well be based on prejudice, and/or
perhaps not enough experience, rather than practice. (A bit like the notion
that always using the std:: prefix makes the code more "unreadable".)

When I have tried in a practical program to divide implementation into
smaller logical functions, I have noticed that it actually improves
the quality of the code. (For instance, in one case I had to make
a specialization of a class, and it turned out to be a lot easier
thanks to the fact that I had divided the base class' implementation
into smaller logical functions, rather than use a few megafunctions.)

Dividing a program into smaller functions doesn't *automatically*
make the program better. Of course you need to put thought into it.
However, when you do, you may find that your program just becomes
better designed.

If you can't easily isolate your nested loop into its own function,
then perhaps that's a sign that your implementation is too complex
and would benefit from a redesign and refactoring.

Mr Flibble

unread,
Nov 20, 2015, 12:23:50 PM11/20/15
to
On 20/11/2015 10:29, Juha Nieminen wrote:
> Mr Flibble <flibbleREM...@i42.co.uk> wrote:
>> Unnecessary functional decomposition can often increase a program's
>> complexity
>
> Citation needed.

I am my own source mate.

> It seems to me that this notion may well be based on prejudice, and/or
> perhaps not enough experience, rather than practice. (A bit like the notion

I've got 30+ years of experience to draw on when making such an
assertion mate sausages.

/Flibble

Öö Tiib

unread,
Nov 20, 2015, 12:42:33 PM11/20/15
to
On Friday, 20 November 2015 09:07:31 UTC+2, Wouter van Ooijen wrote:
> Op 20-Nov-15 om 2:56 AM schreef Öö Tiib:
> > On Friday, 20 November 2015 00:53:52 UTC+2, Ian Collins wrote:
> >> Gareth Owen wrote:
> >>> Personally, I prefer both the goto, and the
> >>>
> >>> class NonLocalExit {};
> >>>
> >>> try {
> >>> ...
> >>> if(found) throw NonLocalExit;
> >>> ...
> >>> }
> >>> catch(const NonLocalExit& e) {}
> >>
> >> That's a terrible abuse of exceptions!
> >
> > +1 Misused exception (thrown and caught in same function) makes that
> > code to look like garbage.
>
> Maybe to your eye, but not necesarily to mine.

Yes to my eye it clearly looks over-engineered bloat. Worthless object
is created thrown and caught instead of just simply jumping out of cycle
or returning out of function.

>
> > Common case like "found" is clear example when *not* to use exceptions.
> > Exceptions are for rare cases (that sometimes happen) like "corrupted",
> > "too_full", "broken", "short_circuited", "timed_out", "unavailable",
> > "underpowered" etc. The operation can not continue and so it breaks
> > with exception thrown up stack. Typically it is caught far since there
> > are nothing to do than to stop the whole feature.
>
> BTW how do you know for sure that (found) is a common case?

To me finding what I search for has never been exceptional case.

>
> > Exception is optimized to have close to no cost when it isn't thrown
> > for being rather expensive when it is thrown. If normal or common
> > condition is signaled with it then that can hurt performance in major
> > way.
>
> Which makes your opinion of how exceptions should be used an example of
> implementation-dependendt optimization. double yuk.

Exceptions are optimized in that way to best support what these are
made for. These are made for (, like name indicates,) handling
exceptional situations. If exceptions are not made efficient for
handling exceptional situations by particular implementation then
that means that the implementation is of low quality.

> I can accept arguments based on readablity, but I abhor premature
> optimization.

Avoiding writing unneeded bloat constructs that are not meant for
purpose under hand and confuse the meaning of code is premature
optimization?

woodb...@gmail.com

unread,
Nov 20, 2015, 1:02:49 PM11/20/15
to
On Friday, November 20, 2015 at 4:23:42 AM UTC-6, Juha Nieminen wrote:
> red floyd <no....@its.invalid> wrote:
> > I'd almost prefer the goto. IMHO, breaking out of nested loops is
> > the only legitimate use of goto.
>
> No, it isn't. "Goto considered harmful" is not just a light quip.
> It's actually quite a useful principle.
>
> The correct way is to put the loop in its own function, and use
> 'return' there.
>
> If your code is such that doing so would be laborious and contrived,
> then that's a sign that you need a redesign. Carefully redesign your
> implementation in such a manner that putting the nested loop in its
> own function becomes natural, clean, understandable and efficient,
> and you will suddenly realize how much better your implementation
> has become overall (ie. not just for this particular nested loop.)
>
> Splitting larger functions into smaller ones, in a logical and
> structured manner, improves the quality and usability of your code.
> You don't need to go overboard with this, but once you start
> having a function with more than, say 20 or 30 lines of code,
> sit back and rethink what you are doing, and whether you could do
> it better.
>

I generally agree with this but have a few event loop functions
that are a little over 100 lines. They used to be longer and
I'm glad to have gotten them to where they are now. One of
them is the cmwAmbassador constructor here - http://webEbenezer.net/misc/cmwAmbassador.cc
.

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

Öö Tiib

unread,
Nov 20, 2015, 1:21:24 PM11/20/15
to
You are correct that compiler may do that.

However when I edit the code and replace that try/throw/catch
bloat with a goto and a label then the code becomes simpler,
easier to read and to understand. So why did I write that
bloat at the first place?

>
> I am not saying that such a use of exceptions is a good idea in general,
> merely that it is not necessarily as inefficient as you think.

I have seen such code in practice at 2010, Visual Studio 2008 did not
optimize it and it was 10 times slower and issue was reported about
bad performance since it happened in some innermost loop. Even if some
more modern compiler can fix it ... I still see no reason to write it.

Gareth Owen

unread,
Nov 20, 2015, 2:08:00 PM11/20/15
to
Ian Collins <ian-...@hotmail.com> writes:

> Gareth Owen wrote:
>> Well, that's exactly what I meant by "lesser of several evils".
>>
>> I happily accept that a function call may well be better than a nested
>> loop with clunky exit mechanism, but it wouldn't necessarily be better
>> than a nested loop with a much cleaner (entirely hypothetical) exit
>> mechanism, with the exit condition stored in the loop construct.
>
> I would usually say it was.

Fair enough. I will happily accept that it sometimes is, but boldly
assert that it sometimes isn't.

Incidentally, TC++PLv3 has some interesting comments on using exceptions
for purposes other than error handling, which I'll precis as "you can do
it, and sometimes it will simplify/clarify an ugly construct ... but you
probably shouldn't without good reason."

<understatement style="massive">
I suspect Bjarne's example (throwing the return-value from a deeply
recursive function) would not be terribly well received here.
</understatement>

Öö Tiib

unread,
Nov 20, 2015, 2:19:24 PM11/20/15
to
On Friday, 20 November 2015 09:04:25 UTC+2, gwowen wrote:
> Ian Collins <ian-...@hotmail.com> writes:
>
> > That's a terrible abuse of exceptions!
>
> They're just another language feature, and one that expresses the
> desired behaviour "jump out of the normal flow of control and resume at
> the end of the loop". It's a goto for people with a fear of 'goto'.


'throw' expresses that anomalous or exceptional condition occurred so
the normal processing can not continue anymore and it is interrupted
and issue is fowarded for special processing somewhere at higher levels.

'try' expresses that something that may fail under anomalous or
exceptional conditions is tried in following block.

'catch' expresses that special processing is in following block.

'throw' inside 'catch' block expresses that only part of special
processing was done (some tidying, cleaning or reverting) and the
issue is forwarded to even higher levels.

Empty 'catch' block indicates that author wants to silence and hide
some defects of his.

> Let the compiler sort out the exit strategy when it optimises the function!
>
> Would you consider it an abuse of exceptions if the (found) condition
> was something that almost never happened?

If you manage to show with convincing tests that it is measurably faster
than 'goto' then I would consider it (potentially unneeded) optimization.
Sometimes every percent of speed is needed so it can be accepted even if
ugly misuse. But I can bet you don't manage to come up with such tests.

Mr Flibble

unread,
Nov 20, 2015, 2:57:41 PM11/20/15
to
I throw an exception to cancel a thread sausages.

/Flibble


Gareth Owen

unread,
Nov 20, 2015, 5:33:07 PM11/20/15
to
Öö Tiib <oot...@hot.ee> writes:

> On Friday, 20 November 2015 09:04:25 UTC+2, gwowen wrote:
>> Ian Collins <ian-...@hotmail.com> writes:
>>
>> > That's a terrible abuse of exceptions!
>>
>> They're just another language feature, and one that expresses the
>> desired behaviour "jump out of the normal flow of control and resume at
>> the end of the loop". It's a goto for people with a fear of 'goto'.
>
> 'throw' expresses that anomalous or exceptional condition occurred so
> the normal processing can not continue anymore and it is interrupted
> and issue is fowarded for special processing somewhere at higher levels.

Unless it doesn't. TC++PLv3 explicitly addresses the fact that while
this is a rule of thumb -- and certainly the most common usage -- its
not a hard and fast rule and you're free - if not necessarily advised -
to use it as just-another-form-of-flow-control.

So, so sorry, but if you're just going to make assertions about
"what <x> is for", I'm going to take the inventor of the language's word
over yours.

Öö Tiib

unread,
Nov 20, 2015, 9:06:03 PM11/20/15
to
On Saturday, 21 November 2015 00:33:07 UTC+2, gwowen wrote:
> Öö Tiib <oot...@hot.ee> writes:
>
> > On Friday, 20 November 2015 09:04:25 UTC+2, gwowen wrote:
> >> Ian Collins <ian-...@hotmail.com> writes:
> >>
> >> > That's a terrible abuse of exceptions!
> >>
> >> They're just another language feature, and one that expresses the
> >> desired behaviour "jump out of the normal flow of control and resume at
> >> the end of the loop". It's a goto for people with a fear of 'goto'.
> >
> > 'throw' expresses that anomalous or exceptional condition occurred so
> > the normal processing can not continue anymore and it is interrupted
> > and issue is fowarded for special processing somewhere at higher levels.
>
> Unless it doesn't. TC++PLv3 explicitly addresses the fact that while
> this is a rule of thumb -- and certainly the most common usage -- its
> not a hard and fast rule and you're free - if not necessarily advised -
> to use it as just-another-form-of-flow-control.

It is true that we should never say "never". However it has to be some
perceivable or measurable advantage when we use something in
non-idiomatic way. Breaking out of range based for is not such
a case.

Usage of exceptions instead of usual flow control within function is
possible but it looks worse and also works less efficiently. Choose a
compiler and show a case when it does not.

> So, so sorry, but if you're just going to make assertions about
> "what <x> is for", I'm going to take the inventor of the language's word
> over yours.

You perhaps misunderstood the book that you read. Its author clearly
always thinks and never does pointless things. Try that as well? What
can be a reason to construct a pointless empty object, throw it out
of loop to catch and to ignore and discard? Is it really better
way to jump out of loop than 'break' or 'goto'?

Gareth Owen

unread,
Nov 21, 2015, 7:40:44 AM11/21/15
to
Öö Tiib <oot...@hot.ee> writes:

[snip weapons-grade assholery]

> What can be a reason to construct a pointless empty object, throw it
> out of loop to catch and to ignore and discard?

To express clearly the intent -- "Jump from here to the matching catch"

> Is it really better way to jump out of loop than 'break' or 'goto'?

Its better than break, because break doesn't work over multiple leves.
It's not better than goto, (which is why I said that I prefer the goto).
But some people simply won't / aren't allowed to use gotos. Usually
people who prefer hard-and-fast rules to thought.

Except where performance is critical, clarity should trump performance.
So unless the throw/catch time dominates the search time (which it
almost never will) *and* the timing of this section determines the
program efficiency, its an irrelevance.

Luca Risolia

unread,
Nov 21, 2015, 2:17:34 PM11/21/15
to
Il 20/11/2015 23:32, Gareth Owen ha scritto:
> Unless it doesn't. TC++PLv3 explicitly addresses the fact that while
> this is a rule of thumb -- and certainly the most common usage -- its
> not a hard and fast rule and you're free - if not necessarily advised -
> to use it as just-another-form-of-flow-control.

I remember that example in TC++PL 3rd edition. If I remember well, there
was also an exercise at the end of the corresponding chapter proposing
to measure the difference between exiting the recursive iterations by
throwing vs using goto or return. I did that exercise with my compiler
and discovered there was not appreciable difference in the timings (I
did not look at any generated code though).

Öö Tiib

unread,
Nov 21, 2015, 5:31:10 PM11/21/15
to
On Saturday, 21 November 2015 14:40:44 UTC+2, gwowen wrote:
> Öö Tiib <oot...@hot.ee> writes:
>
> [snip weapons-grade assholery]

You are pointlessly vulgar there.

>
> > What can be a reason to construct a pointless empty object, throw it
> > out of loop to catch and to ignore and discard?
>
> To express clearly the intent -- "Jump from here to the matching catch"

How can doing those odd things express that intent more clearly than
the jump itself?

>
> > Is it really better way to jump out of loop than 'break' or 'goto'?
>
> Its better than break, because break doesn't work over multiple leves.

You are correct that 'break' does not work there but the actual issue
may be the deeply nested loops themselves.

> It's not better than goto, (which is why I said that I prefer the goto).
> But some people simply won't / aren't allowed to use gotos. Usually
> people who prefer hard-and-fast rules to thought.

I do not care about those people, they are robots and can not be good
engineers. Rules like "avoid goto" but "do whatever with exceptions"
feel rather contradicting and not from this world even for such robots.

Here is link to isocpp FAQ for your robot:
https://isocpp.org/wiki/faq/exceptions#why-not-exceptions

Particular quote:
"In particular, do not use exceptions for control flow. throw is not
simply an alternative way of returning a value from a function (similar
to return). Doing so will be slow and will confuse most C++ programmers
who are rightly used to seeing exceptions used only for error
handling. Similarly, throw is not a good way of getting out of a
loop."

>
> Except where performance is critical, clarity should trump performance.
> So unless the throw/catch time dominates the search time (which it
> almost never will) *and* the timing of this section determines the
> program efficiency, its an irrelevance.

That was my first point. Where is your clarity? Lose-lose-lose situation.
Multiple nested loops can't be over large data sets otherwise such nesting
itself is potential performance bottle-neck.

Juha Nieminen

unread,
Nov 23, 2015, 5:17:20 AM11/23/15
to
Mr Flibble <flibbleREM...@i42.co.uk> wrote:
>> It seems to me that this notion may well be based on prejudice, and/or
>> perhaps not enough experience, rather than practice. (A bit like the notion
>
> I've got 30+ years of experience to draw on when making such an
> assertion mate sausages.

Programmers can demonstrably have prejudices and bad habits lasting for
30+ years. They are not immune to that.

Eric Hart

unread,
Dec 1, 2015, 10:47:46 AM12/1/15
to
> How can doing those odd things express that intent more clearly than
> the jump itself?

100% agree.

> ... Rules like "avoid goto" but "do whatever with exceptions"
> feel rather contradicting ...

Made me laugh!

I have my own C/C++ biases and prejudices formed over nearly 30 years, and "never use goto" was one of them. I've always written the extra test condition on the outer loop. After reading much of this thread, "goto label" used as though it were "break label" sounds perfectly reasonable.

I think I just lost one of my old biases. I probably only have a few thousand left to go...

0 new messages