www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - RFC: Behavior of continue in do/while loops.

reply Downs <default_357-line yahoo.de> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I just came upon the interesting fact that using the "continue"
statement in a do { } while() loop does not, in fact, continue with the
next loop, but instead continues with the _condition_.
I know this is the same behavior as in C, but as somebody who never
encountered it before I can assure you, it's highly unintuitive.
The confusion here stems largely from the way a do/while loop looks -
the condition is found at the _end_ at the loop body, yet I expected
continue to jump to the _beginning_.
There is two questions I want to ask:
First, if you were starting a new language, should the behavior of
continue in that language match what I expected in this case?
(theoretical case)
And second, should the behavior be changed in the D programming
language, even though it _might_ conceivably break code that relies on
the current behavior? (practical case)

Looking forward to your comments,
 --downs
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFG6AvvpEPJRr05fBERAnfQAJ0UapoxtHQCtIfTerkFe3iUnTHXtACfTFj4
ennSYblhmnx1yOzb6izeCfs=
=kBA4
-----END PGP SIGNATURE-----
Sep 12 2007
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Downs" wrote
 I just came upon the interesting fact that using the "continue"
 statement in a do { } while() loop does not, in fact, continue with the
 next loop, but instead continues with the _condition_.
 I know this is the same behavior as in C, but as somebody who never
 encountered it before I can assure you, it's highly unintuitive.
 The confusion here stems largely from the way a do/while loop looks -
 the condition is found at the _end_ at the loop body, yet I expected
 continue to jump to the _beginning_.
 There is two questions I want to ask:
 First, if you were starting a new language, should the behavior of
 continue in that language match what I expected in this case?
 (theoretical case)
My view of the continue statement is that it means "I am done with this iteration of the loop, skip to the next one." In that sense, I think the continue statement works correctly as it is implemented today. BTW, you could implement what you want by using an infinite loop and a break statement. i.e.: do { ... } while(condition) becomes: while(true) { ... if(condition) break; }
 And second, should the behavior be changed in the D programming
 language, even though it _might_ conceivably break code that relies on
 the current behavior? (practical case)
Nope :) Alienating C/Java developers is not a good idea. -Steve
Sep 12 2007
parent reply Downs <default_357-line yahoo.de> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Steven Schveighoffer wrote:
 "Downs" wrote
 I just came upon the interesting fact that using the "continue"
 statement in a do { } while() loop does not, in fact, continue with the
 next loop, but instead continues with the _condition_.
 I know this is the same behavior as in C, but as somebody who never
 encountered it before I can assure you, it's highly unintuitive.
 The confusion here stems largely from the way a do/while loop looks -
 the condition is found at the _end_ at the loop body, yet I expected
 continue to jump to the _beginning_.
 There is two questions I want to ask:
 First, if you were starting a new language, should the behavior of
 continue in that language match what I expected in this case?
 (theoretical case)
My view of the continue statement is that it means "I am done with this iteration of the loop, skip to the next one." In that sense, I think the continue statement works correctly as it is implemented today. BTW, you could implement what you want by using an infinite loop and a break statement. i.e.: do { ... } while(condition) becomes: while(true) { ... if(condition) break; }
Yeah, that's what I ended up doing.
 
 And second, should the behavior be changed in the D programming
 language, even though it _might_ conceivably break code that relies on
 the current behavior? (practical case)
Nope :) Alienating C/Java developers is not a good idea. -Steve
miller[] came up with two good alternatives over in #D 1) forbidding continue in do/while and replacing it with continue do/continue while, or 2) adding goto do/goto while statements. The first one has the advantage of making it totally impossible for a newcomer to trip on this, while the second one has the advantage of not breaking existing code. Whaddya think? --downs -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFG6BnJpEPJRr05fBERAsnFAJ4xcsAi5bkk5JRVa+lM/mv+kafurgCcCU0n /g7nchrjUCIBAW9+EpRgo/g= =TslT -----END PGP SIGNATURE-----
Sep 12 2007
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Downs" wrote
 Steven Schveighoffer wrote:
 Nope :)  Alienating C/Java developers is not a good idea.

 -Steve
miller[] came up with two good alternatives over in #D 1) forbidding continue in do/while and replacing it with continue do/continue while, or 2) adding goto do/goto while statements. The first one has the advantage of making it totally impossible for a newcomer to trip on this, while the second one has the advantage of not breaking existing code. Whaddya think?
I appreciate that you have issues with the continue statement, but I think they are very subtle, and very uncommon. That and the fact that precedence is to have continue re-evaluate the condition will likely result in the language not changing. I look at a do-while loop as a while loop that you want to execute at least once. The whole goal of it was to eliminate having to re-code the loop contents outside the loop so this would occur. What you want seems to me like a *restart* of the loop, not a *continuance*. I think making continue skip the condition is prone to more problems then it is worth (imagine someone switching a while loop to a do-while and then some kind of infinite loop occurs because there was a continue statement). I think adding syntax is not necessary since you can express your version of the loop easily with the current implementation. However, seeing as how I never use goto in my code, and there is precedence for using goto in other constructs (goto case, goto default), I have no problem with adding goto do (goto while is already handled by continue). But it's not up to me :) -Steve
Sep 12 2007
prev sibling next sibling parent reply Regan Heath <regan netmail.co.nz> writes:
Downs wrote:
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1
 
 I just came upon the interesting fact that using the "continue"
 statement in a do { } while() loop does not, in fact, continue with the
 next loop, but instead continues with the _condition_.
 I know this is the same behavior as in C, but as somebody who never
 encountered it before I can assure you, it's highly unintuitive.
 The confusion here stems largely from the way a do/while loop looks -
 the condition is found at the _end_ at the loop body, yet I expected
 continue to jump to the _beginning_.
 There is two questions I want to ask:
 First, if you were starting a new language, should the behavior of
 continue in that language match what I expected in this case?
 (theoretical case)
 And second, should the behavior be changed in the D programming
 language, even though it _might_ conceivably break code that relies on
 the current behavior? (practical case)
 
 Looking forward to your comments,
  --downs
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.7 (GNU/Linux)
 Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
 
 iD8DBQFG6AvvpEPJRr05fBERAnfQAJ0UapoxtHQCtIfTerkFe3iUnTHXtACfTFj4
 ennSYblhmnx1yOzb6izeCfs=
 =kBA4
 -----END PGP SIGNATURE-----
I tend not to use do/while in favour of while and for loops myself so I hadn't really bumped into this behaviour nor needed to imagine what it might do. But, now that I know what it does, thinking about it, I reckon it's the correct (and intuitive - matter of opinion) thing for it to do and I don't think it should change. I suspect whether it is intuitive or not depends on how you think of 'continue', for example: However, if you think of 'continue' as meaning 'go to the next iteration' then you would expect it to do whatever it would have done at the end of this iteration, before the next one. If you think of 'continue' as meaning 'go back to the start of the(this?) loop' then you wouldn't expect the condition to be evaluated. I believe 'go to the next iteration' is the correct interpretation of 'continue'. In do/while, while and for to get from one iteration to the next you have to pass the condition. This is the contract/guarantee that the loop provides. Making the change you suggest will remove this guarantee, making it possible to go from iteration n to iteration n+1 without checking the condition. Despite the fact that the first iteration of do/while should be safe without the guarantee the 2nd-nth ones might not be, eg. if (*input != 0) { char *p = input; do { ..etc.. p++; ..etc.. continue; ..etc.. } while(*p != '\0'); } Regan
Sep 12 2007
parent reply Downs <default_357-line yahoo.de> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Regan Heath wrote
 I suspect whether it is intuitive or not depends on how you think of
 'continue', for example:
 However,  if you think of 'continue' as meaning 'go to the next
 iteration' then you would expect it to do whatever it would have done at
 the end of this iteration, before the next one.
 If you think of 'continue' as meaning 'go back to the start of
 the(this?) loop' then you wouldn't expect the condition to be evaluated.
The problem here is that for every case *but* a do/while loop, the two perspectives behave exactly the same. See my follow-up to the other post for a way to prevent this conflict.
 Regan
- --downs -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFG6Bp5pEPJRr05fBERAuSBAKCLsmjUOiW/+xW+18EMOIs1v5bfkQCfTuvN r1q+L+5LTegmDMgs/V0/VlA= =JjXp -----END PGP SIGNATURE-----
Sep 12 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
Downs wrote:
 However,  if you think of 'continue' as meaning 'go to the next
 iteration' then you would expect it to do whatever it would have done at
 the end of this iteration, before the next one.
 If you think of 'continue' as meaning 'go back to the start of
 the(this?) loop' then you wouldn't expect the condition to be evaluated.
The problem here is that for every case *but* a do/while loop, the two perspectives behave exactly the same. See my follow-up to the other post for a way to prevent this conflict.
I don't agree, 'go back to the start of this loop' simply isn't what 'continue' does, in _any_ case. In all cases when you execute continue you move from iteration n to n+1. Moving from one iteration to the next _always_ involves checking the loop condition. The only difference between do/while and the other loops is that the 1st iteration is 'unprotected' by the guarantee of the loop condition. That's it. Expecting continue to 'go back to the start of this loop' is simply incorrect thinking. If you really want to 'go back to the start of this loop' you have to use goto. I don't really see the point in either of the solutions you have in the other thread, but then "it's not up to me". Regan
Sep 12 2007
parent reply Downs <default_357-line yahoo.de> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Regan Heath wrote:
 Downs wrote:
 However,  if you think of 'continue' as meaning 'go to the next
 iteration' then you would expect it to do whatever it would have done at
 the end of this iteration, before the next one.
 If you think of 'continue' as meaning 'go back to the start of
 the(this?) loop' then you wouldn't expect the condition to be evaluated.
The problem here is that for every case *but* a do/while loop, the two perspectives behave exactly the same. See my follow-up to the other post for a way to prevent this conflict.
I don't agree, 'go back to the start of this loop' simply isn't what 'continue' does, in _any_ case. In all cases when you execute continue you move from iteration n to n+1. Moving from one iteration to the next _always_ involves checking the loop condition.
I know that's not what it _does_, but that wasn't my point. My point was that it _behaves_ the same, as seen from the *outside*, leading to misunderstandings.
 
 The only difference between do/while and the other loops is that the 1st
 iteration is 'unprotected' by the guarantee of the loop condition.
 That's it.
 
 Expecting continue to 'go back to the start of this loop' is simply
 incorrect thinking.  If you really want to 'go back to the start of this
 loop' you have to use goto.
I know that now. The problem is that because the two perspectives are so similar, *despite only one being technically correct*, it's easy to mistake the other one for the correct one if you learned coding by trial-and-error (as I did).
 
 I don't really see the point in either of the solutions you have in the
 other thread, but then "it's not up to me".
The point is to prevent such misunderstandings from occuring again by forcing the programmer to explicitly state what he wants, _independent of his perspective_. So even if he has the wrong idea of how continue actually works (as I did), he'll still be able to get the behavior he expected.
 
 Regan
--downs -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFG6DSkpEPJRr05fBERAuF9AJ4xNOlwp2b6EkLEH1QFHdZ7Fs3oogCeLLog zzpqAwdpoZujDL6HgoOh+Wo= =wGHk -----END PGP SIGNATURE-----
Sep 12 2007
parent Regan Heath <regan netmail.co.nz> writes:
Downs wrote:
 Regan Heath wrote:
 Downs wrote:
 However,  if you think of 'continue' as meaning 'go to the next
 iteration' then you would expect it to do whatever it would have done at
 the end of this iteration, before the next one.
 If you think of 'continue' as meaning 'go back to the start of
 the(this?) loop' then you wouldn't expect the condition to be evaluated.
The problem here is that for every case *but* a do/while loop, the two perspectives behave exactly the same. See my follow-up to the other post for a way to prevent this conflict.
I don't agree, 'go back to the start of this loop' simply isn't what 'continue' does, in _any_ case. In all cases when you execute continue you move from iteration n to n+1. Moving from one iteration to the next _always_ involves checking the loop condition.
I know that's not what it _does_, but that wasn't my point. My point was that it _behaves_ the same, as seen from the *outside*, leading to misunderstandings.
I still don't agree that it "_behaves_ the same, as seen from the *outside*" but I wont labour the point. Regan
Sep 13 2007
prev sibling next sibling parent 0ffh <spam frankhirsch.net> writes:
Hi, downs!

Hmmm, I don't think the behaviour as-is is counterintuitive,
but that's a matter of individual preconditioning, I gather.

Also, the instances of me using the do...while construct are
few and far between, because I consider it looks rather ugly
and seldom find myself in a situation where I'd be forced to
use it (read: where it'd make the code better :-).

Regards, Frank
Sep 12 2007
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Downs" wrote
 The confusion here stems largely from the way a do/while loop looks -
 the condition is found at the _end_ at the loop body, yet I expected
 continue to jump to the _beginning_.
BTW, usually the compiler re-arranges a while loop so that the condition is at the end also. Looks something like this: while(condition) { ... } becomes JMP loop loopstart: ... loop: TST condition ; sets zero flag if condition is true JNZ loopstart Actually, I have no idea how to code in assembly, so my code is probably worthless, but you get the idea :) -Steve
Sep 12 2007
prev sibling next sibling parent renoX <renosky free.fr> writes:
Downs a écrit :
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1
 
 I just came upon the interesting fact that using the "continue"
 statement in a do { } while() loop does not, in fact, continue with the
 next loop, but instead continues with the _condition_.
Yes, that's what I would expect.
 I know this is the same behavior as in C, but as somebody who never
 encountered it before I can assure you, it's highly unintuitive.
Bah, a matter of opinion, I interpret 'continue' as 'continue to the end', why would 'continue to the beginning' more intuitive?
 The confusion here stems largely from the way a do/while loop looks -
 the condition is found at the _end_ at the loop body, yet I expected
 continue to jump to the _beginning_.
But even in a for loop, continue doesn't really continue to the beginning of the loop, it continue to the 'termination test'.
 There is two questions I want to ask:
 First, if you were starting a new language, should the behavior of
 continue in that language match what I expected in this case?
 (theoretical case)
No, current continue behaviour is consistent for while/for/do .. while which is good. Maybe a different keyword could be more intuitive, but I can't find any (skip has the same issue, goto_end is not clear if it's break or continue, etc) unless you want to start using keyword like continue_to_end_of_iteration..
 And second, should the behavior be changed in the D programming
 language, even though it _might_ conceivably break code that relies on
 the current behavior? (practical case)
No: 1) the continue behaviour is coherent. 2) it's consistent with C's behaviour. There are many thing that I dislike in C (stupid variable declaration syntax, use of && for shortcut-and instead of & even though shortcut-and are much more used than binary-and, use 0 to start octal instead of 0o ,etc) but continue isn't one of these (except that it should take a 'loop label' as an optional argument as D's continue does). renoX
 
 Looking forward to your comments,
  --downs
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.7 (GNU/Linux)
 Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
 
 iD8DBQFG6AvvpEPJRr05fBERAnfQAJ0UapoxtHQCtIfTerkFe3iUnTHXtACfTFj4
 ennSYblhmnx1yOzb6izeCfs=
 =kBA4
 -----END PGP SIGNATURE-----
Sep 12 2007
prev sibling next sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Downs wrote

 First, if you were starting a new language, should the behavior of
 continue in that language match what I expected in this case?
 (theoretical case)
No. According to your introduction you might have entangled yourself by trying to optimize away a loop nested in another loop: do{ do{ }while( ); }while( ); -manfred
Sep 12 2007
parent reply Downs <default_357-line yahoo.de> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Manfred Nowak wrote:
 Downs wrote
 
 First, if you were starting a new language, should the behavior of
 continue in that language match what I expected in this case?
 (theoretical case)
No. According to your introduction you might have entangled yourself by trying to optimize away a loop nested in another loop: do{ do{ }while( ); }while( ); -manfred
Actually, I was writing HTTP a downloader and trying to make it embed special-case logic for 1.1 chunks in a 1.0 loop along the lines of do { receive; if (isChunked) { if (chunkedDownloading) continue; break; } } while (notReceivedEnough) so I expected the continue to restart the loop, but it executed the condition (which naturally failed abysmally, because I wasn't doing a normal download :) Doesn't matter, it works now. --downs -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFG6E+JpEPJRr05fBERAp4bAJ9W/K15qgbpPg+P301+rBNeKC/PcACgkVgj 6N0xl0ARvyd5pqcc8kBWKlc= =YDS2 -----END PGP SIGNATURE-----
Sep 12 2007
next sibling parent reply BCS <BCS pathlink.com> writes:
Downs wrote:
 do {
 	receive;
 	if (isChunked) {
 		if (chunkedDownloading) continue;
 		break;
 	}
 } while (notReceivedEnough)
I think this will get you the same result do { receive; } while (isChunked && chunkedDownloading && notReceivedEnough)
Sep 12 2007
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"BCS" <BCS pathlink.com> wrote in message 
news:fc9kjm$28pv$1 digitalmars.com...
 Downs wrote:
 do {
 receive;
 if (isChunked) {
 if (chunkedDownloading) continue;
 break;
 }
 } while (notReceivedEnough)
I think this will get you the same result do { receive; } while (isChunked && chunkedDownloading && notReceivedEnough)
I think it needs to be: while(isChunked && chunkedDownloading || !isChunked && notReceivedEnough) -Steve
Sep 12 2007
parent BCS <ao pathlink.com> writes:
Reply to Steven,

 "BCS" <BCS pathlink.com> wrote in message
 news:fc9kjm$28pv$1 digitalmars.com...
 
 Downs wrote:
 
 do {
 receive;
 if (isChunked) {
 if (chunkedDownloading) continue;
 break;
 }
 } while (notReceivedEnough)
I think this will get you the same result do { receive; } while (isChunked && chunkedDownloading && notReceivedEnough)
I think it needs to be: while(isChunked && chunkedDownloading || !isChunked && notReceivedEnough) -Steve
silly me. I used the current semantics, not what he was looking for.
Sep 12 2007
prev sibling parent Manfred Nowak <svv1999 hotmail.com> writes:
Downs wrote
 do {
      receive;
      if (isChunked) {
           if (chunkedDownloading) continue;
           break;
      }
 } while (notReceivedEnough)
... more entangled than I thought :-) -manfred
Sep 12 2007
prev sibling parent Derek Parnell <derek psych.ward> writes:
On Wed, 12 Sep 2007 17:55:27 +0200, Downs wrote:

 There is two questions I want to ask:
 First, if you were starting a new language, should the behavior of
 continue in that language match what I expected in this case?
 (theoretical case)
Yes.
 And second, should the behavior be changed in the D programming
 language, even though it _might_ conceivably break code that relies on
 the current behavior? (practical case)
No. However, if the introduction of scoped-labels is made, this becomes a simple goto issue. do { top: . . . if (whatever) goto top; . . . } while( some_condition); do { top: . . . if (anothertest) goto top; . . . } while( some_other_condition); At the moment, the scope of labels is too large and you have to invent new label identifiers for each block scope. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Sep 12 2007