loop continuation code

185 views
Skip to first unread message

gmis...@gmail.com

unread,
Jul 25, 2016, 2:40:42 AM7/25/16
to ISO C++ Standard - Future Proposals
Hi

I was recently reading a reddit article where a piece of code like this appeared:

for ( int i = 0; pUnicast != NULL; i++ )
{
   Address address( (sockaddr_storage*) pUnicast->Address.lpSockaddr );

   if ( !address.IsValid() )
      goto next_unicast;

   if ( address.IsLoopback() )
      goto next_unicast;

   if ( address.GetType() == ADDRESS_IPV6 && !address.IsGlobalUnicast() )
      goto next_unicast;

   addresses[numAddresses++] = address;

   if ( numAddresses >= maxAddresses )
      break;

next_unicast:

   pUnicast = pUnicast->Next;
}

A common response to the article was to immediately attack the code and re-write it without using goto because people considered it sloppy. This got me thinking about a few things:

#1 It reminded me how fearful people are of goto so that they won't use it even if it's appropriate; and not only that, but they will also re-write other peoples code using goto to avoid it even if it isn't a big deal. The example loop above isn't that unreasonable especially if you imagine you might want to add additional statements later at the goto target point. That then brings me to my main point:

#2 Sometimes I want to execute the same set of code on continuation and putting it all in the increment section of the loop isn't that nice or even realistic. But using a goto isn't that nice either or having someone re-write code just because *they* don't like goto.

Proposal:
If we had a special continue block in the language, these problems wouldn't exist because we could re-write the above loop like so: 

for ( int i = 0; pUnicast != NULL; i++ )
{
   Address address( (sockaddr_storage*) pUnicast->Address.lpSockaddr );

   if ( !address.IsValid() )
      continue; // goto the continue block below

   if ( address.IsLoopback() )
      continue;

   if ( address.GetType() == ADDRESS_IPV6 && !address.IsGlobalUnicast() )
      continue;

   addresses[numAddresses++] = address;

   if ( numAddresses >= maxAddresses )
      break;

   continue
   {
       // Whatever else you like here.
       pUnicast = pUnicast->Next
   } // on normal exit goto the regular continue point of the loop.
}

This seems useful to me and would solve the points mentioned above and it could be added without introducing any new keywords. It would make goto even less useful and allow use in multiple loops without having to makeup random label names etc. 

The continue block might be better outside of the loop to avoid excessive indentation or at the start inside the loop for clarity. It might also need some re-jigging to get the syntax to play nicely with the "for else" type suggestions I've seen, so bare that in mind too when thinking about this. But you get the basic idea.

I'd appreciate peoples thoughts on the merit of the core idea first and then where they think the continuation block should go.

I expect this feature if adopted would to be available in while and do loops etc. too.

Thanks
GM

D. B.

unread,
Jul 25, 2016, 4:45:07 AM7/25/16
to std-pr...@isocpp.org

Jonathan Müller

unread,
Jul 25, 2016, 4:51:12 AM7/25/16
to std-pr...@isocpp.org

How is that a duplicate? That proposal wants different code executed on the various *break* conditions, this on a *continue*. He even mentions that proposal(s).

D. B.

unread,
Jul 25, 2016, 5:18:31 AM7/25/16
to std-pr...@isocpp.org
On Mon, Jul 25, 2016 at 9:51 AM, Jonathan Müller <jonathanm...@gmail.com> wrote:

How is that a duplicate? That proposal wants different code executed on the various *break* conditions, this on a *continue*. He even mentions that proposal(s).

It seems like a direct extension of the same idea, and lorro mentioned continue in that proposal while discussing how it's quite open-ended in terms of all the 'catch blocks' it could potentially handle. But ymmv.

Nicol Bolas

unread,
Jul 25, 2016, 11:08:23 AM7/25/16
to ISO C++ Standard - Future Proposals, gmis...@gmail.com

I get the idea, but I really don't like the syntax for it. Especially since it's based on a symptom (ie: how you would write it with goto) rather than the problem.

The actual problem is that there are times when your iteration statement can't be a single expression. So what you want is to have a multi-expression iteration statement. So... do that:

for ( int i = 0; pUnicast != NULL;

  pUnicast
= pUnicast->Next; i++)

{
   
Address address( (sockaddr_storage*) pUnicast->Address.lpSockaddr );

   
if ( !address.IsValid() )
     
continue; // goto the continue block below

   
if ( address.IsLoopback() )
     
continue;

   
if ( address.GetType() == ADDRESS_IPV6 && !address.IsGlobalUnicast() )
     
continue;

   addresses
[numAddresses++] = address;

   
if ( numAddresses >= maxAddresses )
     
break;
}

This puts all of the iteration logic in the same place: the `for` statement itself. So if you want to see what happens on each loop, you don't have to look at both the top and the bottom of the `for` statement.

Viacheslav Usov

unread,
Jul 25, 2016, 12:19:25 PM7/25/16
to ISO C++ Standard - Future Proposals, gmis...@gmail.com
On Mon, Jul 25, 2016 at 5:08 PM, Nicol Bolas <jmck...@gmail.com> wrote:

> The actual problem is that there are times when your iteration statement can't be a single expression. So what you want is to have a multi-expression iteration statement.

Since one can already use the comma operator to have multiple expressions in the iteration statement, you probably meant "multi-statement". In which case it should support control structures, and things go crazy very quickly from then on.

Cheers,
V.

Viacheslav Usov

unread,
Jul 25, 2016, 12:38:11 PM7/25/16
to ISO C++ Standard - Future Proposals, gmis...@gmail.com
On Mon, Jul 25, 2016 at 6:19 PM, Viacheslav Usov <via....@gmail.com> wrote:

> Since one can already use the comma operator to have multiple expressions in the iteration statement, you probably meant "multi-statement". In which case it should support control structures, and things go crazy very quickly from then on.

And, in fact, this is something that one can already do in modern C++:

for (int i = 0; i < 5; [&]{ if (i == 0) i = 2; else ++i; }())
printf("%d\n", i);

I generally find the idiom [&]{ /* something */ }() very useful, to the point that I'd like to have some less ugly syntax for it, for example [{ /* something */ }].

Cheers,
V.

gmis...@gmail.com

unread,
Jul 25, 2016, 5:12:12 PM7/25/16
to ISO C++ Standard - Future Proposals, gmis...@gmail.com
Hi Nicol

Thanks for your comments.


On Tuesday, July 26, 2016 at 3:08:23 AM UTC+12, Nicol Bolas wrote:
I get the idea, but I really don't like the syntax for it. Especially since it's based on a symptom (ie: how you would write it with goto) rather than the problem.

I think you correctly understand the problem statement, but I'm less sure from you're wording that you appreciated what I actually proposed and that I too understand the problem statement.
See below:


The actual problem is that there are times when your iteration statement can't be a single expression. So what you want is to have a multi-expression iteration statement. So... do that:

for ( int i = 0; pUnicast != NULL;
  pUnicast
= pUnicast->Next; i++)
This puts all of the iteration logic in the same place: the `for` statement itself. So if you want to see what happens on each loop, you don't have to look at both the top and the bottom of the `for` statement.

Yes that is the problem, but I don't like the existing for loops syntax, so I'm not sure it's meaningful to propose that back to me, especially when my proposal also catered for the logic being at the top of the loop. See:

for ( int i = 0; pUnicast != NULL; )
{
  continue {
  pUnicast = pUnicast->Next;
  ++I;
  }
// whatever
}


I'm hearing you don't like my proposed syntax. let's find a better one then. You are currently holding onto the existing syntax and I don't find that superior to my suggestion for anything but the most trivial of situations. I'm looking for something that scales better for the non trivial situations.


Thanks

gmis...@gmail.com

unread,
Jul 25, 2016, 5:15:20 PM7/25/16
to ISO C++ Standard - Future Proposals, gmis...@gmail.com
Hi V

Thanks for replying.
I think we are in agreement that lambda's don't seem to be solve this problem as cleanly as we'd like.

gmis...@gmail.com

unread,
Jul 25, 2016, 5:37:13 PM7/25/16
to ISO C++ Standard - Future Proposals
That thread seemed more focused on the break aspect and I'm more focused on continue side so I'm obviously reading it the same way as the Jonathan did. You can talk about either in either thread if you want, if you're saying something useful. But I'd suggest talking break there and continue here, especially as I think the problems being addressed warrant their own threads in any case (not that I care strongly). I mainly raised the other thread to alert people that we want to avoid a syntax for either problem that blocks the other. I'm interested in what you actually think of the problems at hand wherever you want to discuss it?

Sean Middleditch

unread,
Jul 25, 2016, 8:01:38 PM7/25/16
to ISO C++ Standard - Future Proposals, gmis...@gmail.com
Or just remove the variable i from the loop entirely because it's unused in the loop body, thus reducing the for statement to:

    for(; pUnicast != nullptr; pUnicat = pUnicast->Next)

Not that a multi-statement increment wouldn't be useful, but this code snippet is a pretty terrible motivating example. Sorry Glenn! :)

Anecdotally though (not that anyone cares, nor should you), I can't recall a time I ever felt that I needed multiple loop incrementees without eventually realizing that I was just writing my loop like an idiot. Or missing an easily-written library facility to use with for-range iterator. :)

gmis...@gmail.com

unread,
Jul 25, 2016, 8:57:39 PM7/25/16
to ISO C++ Standard - Future Proposals, gmis...@gmail.com


On Tuesday, July 26, 2016 at 12:01:38 PM UTC+12, Sean Middleditch wrote:
Or just remove the variable i from the loop entirely because it's unused in the loop body, thus reducing the for statement to:

    for(; pUnicast != nullptr; pUnicat = pUnicast->Next)

Not that a multi-statement increment wouldn't be useful, but this code snippet is a pretty terrible motivating example. Sorry Glenn! :)

It's just some code I saw on reddit. But c'mon, you're being as unimaginative here as I've been lazy in crimping some random code to demonstrate the use case! lol
I'm not suggesting the need is desperate, but I have myself a few times in the past written loops where I've realised that I'd like to "continue early" a few times - much like returning early - to avoid complicating later code with logic just to avoid it being hit. But I'd still like to do something a bit more significant on each continue occasionally and not want to repeat that code or to have to try to shoe horn that logic into the increment statement of the loop or use a comma there where it just feels wrong and is too constrained.

I don't think you need to be that imaginative to see that ;) but hey I'm sure you won't be alone in your opinion if you still don't agree. I perhaps should contact the author of the original code and see if they agree if this facility would encourage them to use it over goto. That would a be a little interesting to me.

Thanks for your feedback.

Miro Knejp

unread,
Jul 25, 2016, 9:12:43 PM7/25/16
to std-pr...@isocpp.org
Am 26.07.2016 um 02:57 schrieb gmis...@gmail.com:


On Tuesday, July 26, 2016 at 12:01:38 PM UTC+12, Sean Middleditch wrote:
Or just remove the variable i from the loop entirely because it's unused in the loop body, thus reducing the for statement to:

    for(; pUnicast != nullptr; pUnicat = pUnicast->Next)

Not that a multi-statement increment wouldn't be useful, but this code snippet is a pretty terrible motivating example. Sorry Glenn! :)

It's just some code I saw on reddit. But c'mon, you're being as unimaginative here as I've been lazy in crimping some random code to demonstrate the use case! lol
I'm not suggesting the need is desperate, but I have myself a few times in the past written loops where I've realised that I'd like to "continue early" a few times - much like returning early - to avoid complicating later code with logic just to avoid it being hit. But I'd still like to do something a bit more significant on each continue occasionally and not want to repeat that code or to have to try to shoe horn that logic into the increment statement of the loop or use a comma there where it just feels wrong and is too constrained.

I don't think you need to be that imaginative to see that ;) but hey I'm sure you won't be alone in your opinion if you still don't agree. I perhaps should contact the author of the original code and see if they agree if this facility would encourage them to use it over goto. That would a be a little interesting to me.
The thing is that papers proposing language changes always need a pretty good and convincing motivation section that clearly shows how the language feature improves the status-quo. "... I have myself in the past written loops where ..." doesn't really cut it without showing (optimally real world) examples where any other alternative using existing language (or even other proposals) is inferior. You have to convince some 100+ experts that your feature is the way to go and have answers prepared for the inevitable opposition/criticism.

gmis...@gmail.com

unread,
Jul 25, 2016, 9:52:51 PM7/25/16
to ISO C++ Standard - Future Proposals

The thing is that papers proposing language changes always need a pretty good and convincing motivation section that clearly shows how the language feature improves the status-quo. "... I have myself in the past written loops where ..." doesn't really cut it without showing (optimally real world) examples where any other alternative using existing language (or even other proposals) is inferior. You have to convince some 100+ experts that your feature is the way to go and have answers prepared for the inevitable opposition/criticism.


For anyone who has encountered the problem themselves AND sees it as a sufficient problem I'm sure they can imagine a motivating case already. If not, they are simply in the set of people who don't find this issue motivating, so they never will be. Let's be realistic. I'm ok with that. And in any case I'm not going to create an implementation or do any other things that people might have on there wish list, I'm just throwing the idea out there and if that motivates an expert to run with the idea great, if not, that's ok too as I'm sure there time is more valuable than mine. But I don't buy that imagination here is the problem. So you're one of the people unmotivated by the idea, I'm ok with that. But let's not pretend anything would convince you I think you are kidding yourself.

Nicol Bolas

unread,
Jul 25, 2016, 10:47:08 PM7/25/16
to ISO C++ Standard - Future Proposals, gmis...@gmail.com
On Monday, July 25, 2016 at 5:12:12 PM UTC-4, gmis...@gmail.com wrote:
Hi Nicol

Thanks for your comments.

On Tuesday, July 26, 2016 at 3:08:23 AM UTC+12, Nicol Bolas wrote:
I get the idea, but I really don't like the syntax for it. Especially since it's based on a symptom (ie: how you would write it with goto) rather than the problem.

I think you correctly understand the problem statement, but I'm less sure from you're wording that you appreciated what I actually proposed and that I too understand the problem statement.
See below:

The actual problem is that there are times when your iteration statement can't be a single expression. So what you want is to have a multi-expression iteration statement. So... do that:

for ( int i = 0; pUnicast != NULL;
  pUnicast
= pUnicast->Next; i++)
This puts all of the iteration logic in the same place: the `for` statement itself. So if you want to see what happens on each loop, you don't have to look at both the top and the bottom of the `for` statement.
Yes that is the problem, but I don't like the existing for loops syntax, so I'm not sure it's meaningful to propose that back to me, especially when my proposal also catered for the logic being at the top of the loop. See:

for ( int i = 0; pUnicast != NULL; )
{
  continue {
  pUnicast = pUnicast->Next;
  ++I;
  }
// whatever
}

I fail to see how that is in any way better syntax than what I suggested. Indeed, it's worse because it gives the writer the choice of where this "continue" block is.

A reader of a `for` loop should not have to scan through the loop's body just to find out how it iterates through its stuff.

I'm hearing you don't like my proposed syntax. let's find a better one then. You are currently holding onto the existing syntax and I don't find that superior to my suggestion for anything but the most trivial of situations. I'm looking for something that scales better for the non trivial situations.

What is a "non-trivial situation"? That's kinds the problem with your idea: this use case simply doesn't happen *that* often.

`for` is nothing more than syntactic sugar for `while`. But most of us use `for` more often than `while`, so that proves the usefulness of the syntactic sugar. Range-based `for` is the same way; it's exceptionally handy in a lot of cases.

Most uses of `for` loops are just fine with a simple iteration statement. The number of times when a `for` loop gets so complex that you need multiple counter statements (not just expressions but actual statements) is quite low.

In those cases, `goto` is the proper tool. That's why we keep it around, after all. Not because it's useful most of the time. Or some of the time. Or even rarely. But for that 1:10000 case when we have to do something unorthodox, something that our existing abstractions cannot cleanly handle. We take the tool off the shelf and use it to get things done in a reasonable way.

We should not add syntax for exceptionally rare circumstances. Indeed, in code review, if there was no legitimate way to clean up that loop, I would prefer that it be written as a `while` loop, thus forcing the coding style. By doing so, we make it abundantly clear that the loop's logic doesn't follow the standard `for` rules. `for` exists for trivial circumstances; if your circumstances are non-trivial, then it's simply the wrong tool.

On Monday, July 25, 2016 at 9:52:51 PM UTC-4, gmis...@gmail.com wrote:

The thing is that papers proposing language changes always need a pretty good and convincing motivation section that clearly shows how the language feature improves the status-quo. "... I have myself in the past written loops where ..." doesn't really cut it without showing (optimally real world) examples where any other alternative using existing language (or even other proposals) is inferior. You have to convince some 100+ experts that your feature is the way to go and have answers prepared for the inevitable opposition/criticism.


For anyone who has encountered the problem themselves AND sees it as a sufficient problem I'm sure they can imagine a motivating case already. If not, they are simply in the set of people who don't find this issue motivating, so they never will be. Let's be realistic. I'm ok with that. And in any case I'm not going to create an implementation or do any other things that people might have on there wish list, I'm just throwing the idea out there and if that motivates an expert to run with the idea great, if not, that's ok too as I'm sure there time is more valuable than mine. But I don't buy that imagination here is the problem. So you're one of the people unmotivated by the idea, I'm ok with that. But let's not pretend anything would convince you I think you are kidding yourself.

So your response to being asked to provide motivation for your proposal is to simply claim that people who are asking for it will never understand. so there's no point in giving it to them. I can't say that I find such an "argument" convincing...

gmis...@gmail.com

unread,
Jul 25, 2016, 11:26:55 PM7/25/16
to ISO C++ Standard - Future Proposals, gmis...@gmail.com
Hi Nicol
 


I fail to see how that is in any way better syntax than what I suggested. Indeed, it's worse because it gives the writer the choice of where this "continue" block is.

A reader of a `for` loop should not have to scan through the loop's body just to find out how it iterates through its stuff.

Why don't you actually read what I said in my proposal instead of randomly making stuff up and being patronising?
I never said a user should "have to" do anything. What I actually said was the notion of a continue block supports being anywhere so the concept supports being as flexible as people like, but I'd like people to vote for where they'd like it to go. I get you'd like it at the beginning, great, me too! But let's not keep attributing me to something I didn't say. For someone who doesn't like "scanning" you seem to be doing a lot of it.

 

I'm hearing you don't like my proposed syntax. let's find a better one then. You are currently holding onto the existing syntax and I don't find that superior to my suggestion for anything but the most trivial of situations. I'm looking for something that scales better for the non trivial situations.

What is a "non-trivial situation"? That's kinds the problem with your idea: this use case simply doesn't happen *that* often.

I never said it did happen *all that often*.
 

`for` is nothing more than syntactic sugar for `while`. But most of us use `for` more often than `while`, so that proves the usefulness of the syntactic sugar. Range-based `for` is the same way; it's exceptionally handy in a lot of cases.

Most uses of `for` loops are just fine with a simple iteration statement. The number of times when a `for` loop gets so complex that you need multiple counter statements (not just expressions but actual statements) is quite low.

In those cases, `goto` is the proper tool. That's why we keep it around, after all. Not because it's useful most of the time. Or some of the time. Or even rarely. But for that 1:10000 case when we have to do something unorthodox, something that our existing abstractions cannot cleanly handle. We take the tool off the shelf and use it to get things done in a reasonable way.

I explained why I think goto isn't sufficing here. Look at the people who wanted to rewrite the original sample (from reddit) without the goto. goto attracts so much hate it gets attacked even when it is appropriate. This idea was to help in those cases an alternative to side step some of that. If you don't think so, that's ok.
 
 

We should not add syntax for exceptionally rare circumstances. Indeed, in code review, if there was no legitimate way to clean up that loop, I would prefer that it be written as a `while` loop, thus forcing the coding style. By doing so, we make it abundantly clear that the loop's logic doesn't follow the standard `for` rules. `for` exists for trivial circumstances; if your circumstances are non-trivial, then it's simply the wrong tool.

On Monday, July 25, 2016 at 9:52:51 PM UTC-4, gmis...@gmail.com wrote:

The thing is that papers proposing language changes always need a pretty good and convincing motivation section that clearly shows how the language feature improves the status-quo. "... I have myself in the past written loops where ..." doesn't really cut it without showing (optimally real world) examples where any other alternative using existing language (or even other proposals) is inferior. You have to convince some 100+ experts that your feature is the way to go and have answers prepared for the inevitable opposition/criticism.


For anyone who has encountered the problem themselves AND sees it as a sufficient problem I'm sure they can imagine a motivating case already. If not, they are simply in the set of people who don't find this issue motivating, so they never will be. Let's be realistic. I'm ok with that. And in any case I'm not going to create an implementation or do any other things that people might have on there wish list, I'm just throwing the idea out there and if that motivates an expert to run with the idea great, if not, that's ok too as I'm sure there time is more valuable than mine. But I don't buy that imagination here is the problem. So you're one of the people unmotivated by the idea, I'm ok with that. But let's not pretend anything would convince you I think you are kidding yourself.

So your response to being asked to provide motivation for your proposal is to simply claim that people who are asking for it will never understand. so there's no point in giving it to them. I can't say that I find such an "argument" convincing...

Don't be convinced then, that's ok. But I'm also allowed to find it unconvincing that anything will convince you and that's my prerogative too because this isn't a rocket science suggestion regardless of whatever rocket science you think it needs to back it up. It was an off the cuff idea and I've claimed no great effort to sell it as anything more than that. So how about next time you at least make an effort to read what I actually wrote to begin with before patronising me or attributing things to me that I didn't say like where you "have to" put the continue block. It seems you have no ability to add to or mould an idea or even gently inquire about it, only just nuke everything from a great height. I don't find that approach very convincing to anything no matter how smart you are.

Viacheslav Usov

unread,
Jul 26, 2016, 8:44:15 AM7/26/16
to ISO C++ Standard - Future Proposals
On Mon, Jul 25, 2016 at 11:15 PM, <gmis...@gmail.com> wrote:

> I think we are in agreement that lambda's don't seem to be solve this problem as cleanly as we'd like.

I think you have not demonstrated what "this problem" really is. This is probably what the others in this thread have said.

You seem to want some new syntax for some very rare use case, not because the current language means cannot handle that case, but because you dislike those means, and, as far as I can tell, you have not given any substantial technical reasons for your dislike. I doubt this will be universally regarded as a problem worth fixing.

Cheers,
V.

gmis...@gmail.com

unread,
Jul 26, 2016, 10:34:13 AM7/26/16
to ISO C++ Standard - Future Proposals
There is nothing more to state because the idea isn't complex. It is what it appears be - a simple syntax for a small problem where the existing syntax is workable but clumsy. If you're just saying you and the majority so far think it' isn't a problem worth fixing, I agree that's what they are saying and what I expected. But the idea is simple as is the problem so if it doesn't sell it self, it won't, so I won't defend it because it's pointless given what I believe. If people like the idea, great, if they don't, ok too, just argue amongst yourselves about it. If people get beyond just saying they don't like the idea or mischaracterising what I said to begin with on the subject, I might join the conversation later, but until some more interesting is said, leave me out of it.

szollos...@gmail.com

unread,
Jul 28, 2016, 10:50:18 AM7/28/16
to ISO C++ Standard - Future Proposals, gmis...@gmail.com
Hi,

Just to jump in :), I was the one who wrote the other idea-for-proposal mail and I'd be more than happy to merge the two threads. My intention on the other thread is to re-think all the looping concepts of C++, possibly by getting feedback from other languages' users and come up with a set of possible extensions like a tick list. This includes schematics and syntax. That way, when/if we'll propose it to the Std's Committee, they'll have options rather than me myself saying what's the best solution.
That said, don't expect that thread to be quick. I'd rather make a proper proposal once than 20 revisions.

Regards,
-lorro
Reply all
Reply to author
Forward
0 new messages