www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Proposal of a general do-while loop

reply Taro Kawagishi <tarok acm.org> writes:
Hello all,

every once in a while I feel uneasy when I find I can't fit my logic into a
do-while or while loop in a concise way.
Here is a C++ example:

void
find_string_occurrences(const string& text, const string& pattern) {

    // listing 1
    size_t pos = text.find(pattern, 0);
    while (pos != string::npos) {
        cout << "pattern found at " << pos << "\n";
        ++pos;
        pos = text.find(pattern, pos);
    }

}

The way the code is written might look redundant in calling find() twice, but I
think it is reasonable because you can test the loop condition only after you
run function find() but here you can't use a do-while loop which doesn't allow
you to place other statements after the condition statement.

I can write the same logic as in listing 2 and 3 below, but their meanings
would be less clear than listing 1, because the looping condition is in the if
statement together with the break statement in it, and you need to spot the if
statement in the while body to understand it.

    // listing 2
    size_t pos = 0;
    while (true) {
        pos = text.find(pattern, pos);
        if (pos == string::npos) {
            break;
        }
        cout << "pattern found at " << pos << "\n";
        ++pos;
    }

    // listing 3
    size_t pos = 0;
    do {
        pos = text.find(pattern, pos);
        if (pos == string::npos) {
            break;
        }
        cout << "pattern found at " << pos << "\n";
        ++pos;
    } while (true);

I think a more natural way to express the logic is to write the code as in
listing 4.

    // listing 4
    size_t pos = 0;
    do {
        pos = text.find(pattern, pos);
    } while (pos != string::npos) {
        cout << "pattern found at " << pos << "\n";
        ++pos;
    }

The meaning of

    do {
        aa;
    } while (bb) {
        cc;
    }

is

    while (true) {
        aa;
        if (not bb) {
            break;
        }
        cc;
    }

and is a natural extension to both of

    do {
        aa;
    } while (bb);

and

    while (bb) {
        cc;
    }

The current while loop and do-while loop will be specialized forms of this
general do-while loop.

The advantage of the new construct will be seen if you have more complex
statements within do and while blocks.
I believe allowing this extended construct will be smooth since it will not
break the existing code.
I think D language would be a great fit to have this feature because the
language seems to be still evolving.
Jul 17 2007
next sibling parent reply Gregor Richards <Richards codu.org> writes:
while ((pos = text.find(pattern, pos)) != string::npos) {
     ...
}


Yeesh.

  - Gregor Richards
Jul 17 2007
parent janderson <askme me.com> writes:
Gregor Richards wrote:
 while ((pos = text.find(pattern, pos)) != string::npos) {
     ...
 }
 
 
 Yeesh.
 
  - Gregor Richards
I agree this is the best way to solve this particular problem. How much different is? while ((pos = text.find(pattern, pos)) != string::npos) { ... } from do {pos = text.find(pattern, pos)} while (pos != string::npos) { ... } do/while may be more neat if you have more then one pre-condition however.
Jul 21 2007
prev sibling next sibling parent Regan Heath <regan netmail.co.nz> writes:
for (size_t pos = text.find(pattern, 0); pos != string::npos; pos = 
text.find(pattern, pos)) {
     cout << "pattern found at " << pos << "\n";
     ++pos;
}
Jul 17 2007
prev sibling next sibling parent Alex Burton <alexibu mac.com> writes:
I agree with Taro.

I also have felt this uneasiness with this type of loop.

I think it is an excellent proposal.
Jul 17 2007
prev sibling next sibling parent Tomas Lindquist Olsen <tomas famolsen.dk> writes:
On Tue, 17 Jul 2007 03:04:11 -0400, Taro Kawagishi wrote:

 Hello all,
 
 every once in a while I feel uneasy when I find I can't fit my logic into
 a do-while or while loop in a concise way. Here is a C++ example:
 
 void
 find_string_occurrences(const string& text, const string& pattern) {
 
     // listing 1
     size_t pos = text.find(pattern, 0);
     while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n"; ++pos;
         pos = text.find(pattern, pos);
     }
     }
 
 }
 The way the code is written might look redundant in calling find() twice,
 but I think it is reasonable because you can test the loop condition only
 after you run function find() but here you can't use a do-while loop which
 doesn't allow you to place other statements after the condition statement.
 
 I can write the same logic as in listing 2 and 3 below, but their meanings
 would be less clear than listing 1, because the looping condition is in
 the if statement together with the break statement in it, and you need to
 spot the if statement in the while body to understand it.
 
     // listing 2
     size_t pos = 0;
     while (true) {
         pos = text.find(pattern, pos);
         if (pos == string::npos) {
             break;
         }
         cout << "pattern found at " << pos << "\n"; ++pos;
     }
     }
     // listing 3
     size_t pos = 0;
     do {
         pos = text.find(pattern, pos);
         if (pos == string::npos) {
             break;
         }
         cout << "pattern found at " << pos << "\n"; ++pos;
     } while (true);
 
 I think a more natural way to express the logic is to write the code as in
 listing 4.
 
     // listing 4
     size_t pos = 0;
     do {
         pos = text.find(pattern, pos);
     } while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n"; ++pos;
     }
     }
 The meaning of
 
     do {
         aa;
     } while (bb) {
         cc;
     }
     }
 is
 
     while (true) {
         aa;
         if (not bb) {
             break;
         }
         cc;
     }
     }
 and is a natural extension to both of
 
     do {
         aa;
     } while (bb);
 
 and
 
     while (bb) {
         cc;
     }
     }
 The current while loop and do-while loop will be specialized forms of this
 general do-while loop.
 
 The advantage of the new construct will be seen if you have more complex
 statements within do and while blocks. I believe allowing this extended
 construct will be smooth since it will not break the existing code. I
 think D language would be a great fit to have this feature because the
 language seems to be still evolving.
I dont see any reason to further complicate the language for this. As you already pointed out yourself it can be easily accomplished with the current language features. Here's mine: for(;;) { aa; if (!cond) break; bb; } - Tomas
Jul 17 2007
prev sibling next sibling parent reply Don Clugston <dac nospam.com.au> writes:
Taro Kawagishi wrote:
 Hello all,
 
 every once in a while I feel uneasy when I find I can't fit my logic into a
do-while or while loop in a concise way.
 Here is a C++ example:
 
 void
 find_string_occurrences(const string& text, const string& pattern) {
 
     // listing 1
     size_t pos = text.find(pattern, 0);
     while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n";
         ++pos;
         pos = text.find(pattern, pos);
     }
 
 }
 
 The way the code is written might look redundant in calling find() twice, but
I think it is reasonable because you can test the loop condition only after you
run function find() but here you can't use a do-while loop which doesn't allow
you to place other statements after the condition statement.
 
 I can write the same logic as in listing 2 and 3 below, but their meanings
would be less clear than listing 1, because the looping condition is in the if
statement together with the break statement in it, and you need to spot the if
statement in the while body to understand it.
 
     // listing 2
     size_t pos = 0;
     while (true) {
         pos = text.find(pattern, pos);
         if (pos == string::npos) {
             break;
         }
         cout << "pattern found at " << pos << "\n";
         ++pos;
     }
 
     // listing 3
     size_t pos = 0;
     do {
         pos = text.find(pattern, pos);
         if (pos == string::npos) {
             break;
         }
         cout << "pattern found at " << pos << "\n";
         ++pos;
     } while (true);
 
 I think a more natural way to express the logic is to write the code as in
listing 4.
 
     // listing 4
     size_t pos = 0;
     do {
         pos = text.find(pattern, pos);
     } while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n";
         ++pos;
     }
 
 The meaning of
 
     do {
         aa;
     } while (bb) {
         cc;
     }
 
 is
 
     while (true) {
         aa;
         if (not bb) {
             break;
         }
         cc;
     }
 
 and is a natural extension to both of
 
     do {
         aa;
     } while (bb);
 
 and
 
     while (bb) {
         cc;
     }
 
 The current while loop and do-while loop will be specialized forms of this
general do-while loop.
 
 The advantage of the new construct will be seen if you have more complex
statements within do and while blocks.
 I believe allowing this extended construct will be smooth since it will not
break the existing code.
 I think D language would be a great fit to have this feature because the
language seems to be still evolving.
 
Forth has this construct in the form of a BEGIN ... WHILE ... REPEAT loop. I don't think I've seen it elsewhere, though. Uses for it come up fairly frequently in my experience, but as others have mentioned, the for(;;) { aa; if (cond) break; bb; } idiom isn't too bad. Walter uses 'goto' more than any other programmer I've ever seen. Search through Phobos and the DMD front-end for 'goto', and see how many could be replaced by your do-while loop. Is it a significant fraction of the total?
Jul 17 2007
next sibling parent Jeff Nowakowski <jeff dilacero.org> writes:
Don Clugston wrote:
 Walter uses 'goto' more than any other programmer I've ever seen.
Now there's a good D usenet sig :) -Jeff
Jul 17 2007
prev sibling parent reply BCS <ao pathlink.com> writes:
Reply to Don,

 Walter uses 'goto' more than any other programmer I've ever seen.
I'd do this: goto mid; while(bb) { cc; mid: aa; }
Jul 17 2007
parent reply Tristam MacDonald <swiftcoder gmail.com> writes:
While we are at it, why not just this?

goto mid;
begin:
cc;
mid:
aa;
if (bb) goto begin;

Clear concise and simple, plus it is much closer to the actual machine logic,
and so may imrpove performance as much as -1% ;)

BCS Wrote:

 Reply to Don,
 
 Walter uses 'goto' more than any other programmer I've ever seen.
I'd do this: goto mid; while(bb) { cc; mid: aa; }
Jul 17 2007
parent reply BCS <ao pathlink.com> writes:
Reply to Tristam,

 While we are at it, why not just this?
 
 goto mid;
 begin:
 cc;
 mid:
 aa;
 if (bb) goto begin;
 Clear concise and simple, plus it is much closer to the actual machine
 logic, and so may imrpove performance as much as -1% ;)
 
While your point is relevant, the actual reason for doing it the way I pointed out is not performance, but the removal of duplicate source code. I am a firm believer in the assertion that anytime you have duplication of code[*], you have a bug waiting to happen. Except for the goto, my example read reasonably clearly and does a reasonable job of describing what is intended. The original proposal and the other examples (except maybe the if()break; example) are not, IMHO, so clear. If you can think of a better way to show the intent, I'm interested. *IIRC the XP folks will agree with me, however I'm only looking at code that is /exactly/ the same, not just abstractable to the same thing.
Jul 17 2007
parent Tristam MacDonald <swiftcoder gmail.com> writes:
The point I was trying to make is that while any thing *can* be done through
tricky code, the do {} while {} is such a common problem that I agree with the
OP that it *should* have a distinct syntactical representation.
Intoducing such a basic syntax element to C/C++ at this stage would be nigh
impossible, but D is young enough to adopt something like this, and something
which simplifies syntax and readability is IMHO worth considering.

BCS Wrote:

 Reply to Tristam,
 
 While we are at it, why not just this?
 
 goto mid;
 begin:
 cc;
 mid:
 aa;
 if (bb) goto begin;
 Clear concise and simple, plus it is much closer to the actual machine
 logic, and so may imrpove performance as much as -1% ;)
 
While your point is relevant, the actual reason for doing it the way I pointed out is not performance, but the removal of duplicate source code. I am a firm believer in the assertion that anytime you have duplication of code[*], you have a bug waiting to happen. Except for the goto, my example read reasonably clearly and does a reasonable job of describing what is intended. The original proposal and the other examples (except maybe the if()break; example) are not, IMHO, so clear. If you can think of a better way to show the intent, I'm interested. *IIRC the XP folks will agree with me, however I'm only looking at code that is /exactly/ the same, not just abstractable to the same thing.
Jul 17 2007
prev sibling next sibling parent reply downs <default_357-line yahoo.de> writes:
Taro Kawagishi wrote:
 I think a more natural way to express the logic is to write the code as in
listing 4.
 
     // listing 4
     size_t pos = 0;
     do {
         pos = text.find(pattern, pos);
     } while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n";
         ++pos;
     }
 
 The meaning of
 
     do {
         aa;
     } while (bb) {
         cc;
     }
 
 is
 
     while (true) {
         aa;
         if (not bb) {
             break;
         }
         cc;
     }
void doWhile(void delegate() pre, lazy bool cond, void delegate() post) { while (true) { pre; if (!cond()) break; post; } } // listing 4, modified size_t pos=0; doWhile ({ pos=text.find(pattern, pos); }, pos!=string::npos, { writefln("Pattern found at ", pos); ++pos; }); Not tested, but should work. Have fun!
Jul 17 2007
next sibling parent downs <default_357-line yahoo.de> writes:
downs wrote:
 void doWhile(void delegate() pre, lazy bool cond, void delegate() post) {
   while (true) {
     pre;
Er, naturally, that has to be pre();
     if (!cond()) break;
     post;
And post();
   }
 }
Jul 17 2007
prev sibling next sibling parent reply downs <default_357-line yahoo.de> writes:
Here's a more generic version. This one was tested and shown to work.
Have fun with it!
  --downs
=======================================================================
import std.stdio, std.string;

/// Cond is
void doWhile(P, C, O)(lazy P pre, lazy C cond, lazy O post) {
   while (true) {
     static if (is(P==void delegate())) pre()(); else pre();
     if (!cond()) break;
     static if (is(O==void delegate())) post()(); else post();
   }
}

// these are the things stupid std.string forces us to do.
// Tango, with str.length==NOTFOUND, really picked the better approach.
int find(char[] str, char[] match, int offset) {
   auto res=std.string.find(str[offset..$], match);
   if (res==-1) return -1;
   return res+offset;
}

void main() {
   int pos=0;
   auto text="This interestingly works.";
   // Note the way we can switch between using brackets and not using them.
   doWhile(
     pos=text.find("i", pos),
     pos+1, /// equivalent to pos!=-1, except it also demonstrates
            /// that the conditional can be anything "if" can use.
     { writefln("Hit at ", pos); ++pos; }
   );
}
Jul 17 2007
next sibling parent Taro Kawagishi <tarok acm.org> writes:
downs Wrote:

 Here's a more generic version. This one was tested and shown to work.
 Have fun with it!
   --downs
 =======================================================================
 import std.stdio, std.string;
 
 /// Cond is
 void doWhile(P, C, O)(lazy P pre, lazy C cond, lazy O post) {
    while (true) {
      static if (is(P==void delegate())) pre()(); else pre();
      if (!cond()) break;
      static if (is(O==void delegate())) post()(); else post();
    }
 }
 
 // these are the things stupid std.string forces us to do.
 // Tango, with str.length==NOTFOUND, really picked the better approach.
 int find(char[] str, char[] match, int offset) {
    auto res=std.string.find(str[offset..$], match);
    if (res==-1) return -1;
    return res+offset;
 }
 
 void main() {
    int pos=0;
    auto text="This interestingly works.";
    // Note the way we can switch between using brackets and not using them.
    doWhile(
      pos=text.find("i", pos),
      pos+1, /// equivalent to pos!=-1, except it also demonstrates
             /// that the conditional can be anything "if" can use.
      { writefln("Hit at ", pos); ++pos; }
    );
 }
I am new to D, and this is quite impressive. I guess we can do a similar thing with function objects in C++. However my original intention was to do simple things in a simple way. -Taro
Jul 18 2007
prev sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
downs wrote:
 Here's a more generic version. This one was tested and shown to work.
 Have fun with it!
  --downs
 =======================================================================
 import std.stdio, std.string;
 
 /// Cond is
 void doWhile(P, C, O)(lazy P pre, lazy C cond, lazy O post) {
   while (true) {
     static if (is(P==void delegate())) pre()(); else pre();
     if (!cond()) break;
     static if (is(O==void delegate())) post()(); else post();
   }
 }
 
 // these are the things stupid std.string forces us to do.
 // Tango, with str.length==NOTFOUND, really picked the better approach.
 int find(char[] str, char[] match, int offset) {
   auto res=std.string.find(str[offset..$], match);
   if (res==-1) return -1;
   return res+offset;
 }
 
 void main() {
   int pos=0;
   auto text="This interestingly works.";
   // Note the way we can switch between using brackets and not using them.
   doWhile(
     pos=text.find("i", pos),
     pos+1, /// equivalent to pos!=-1, except it also demonstrates
            /// that the conditional can be anything "if" can use.
     { writefln("Hit at ", pos); ++pos; }
   );
 }
The usage can also be: doWhile( pos=text.find("i", pos), pos+1, (writefln("Hit at ", pos), ++pos ) ); Only one char less though :P -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Jul 18 2007
parent reply Steve Teale <steve.teale britseyeview.com> writes:
Bruno Medeiros Wrote:

 downs wrote:
 Here's a more generic version. This one was tested and shown to work.
 Have fun with it!
  --downs
 =======================================================================
 import std.stdio, std.string;
 
 /// Cond is
 void doWhile(P, C, O)(lazy P pre, lazy C cond, lazy O post) {
   while (true) {
     static if (is(P==void delegate())) pre()(); else pre();
     if (!cond()) break;
     static if (is(O==void delegate())) post()(); else post();
   }
 }
 
 // these are the things stupid std.string forces us to do.
 // Tango, with str.length==NOTFOUND, really picked the better approach.
 int find(char[] str, char[] match, int offset) {
   auto res=std.string.find(str[offset..$], match);
   if (res==-1) return -1;
   return res+offset;
 }
 
 void main() {
   int pos=0;
   auto text="This interestingly works.";
   // Note the way we can switch between using brackets and not using them.
   doWhile(
     pos=text.find("i", pos),
     pos+1, /// equivalent to pos!=-1, except it also demonstrates
            /// that the conditional can be anything "if" can use.
     { writefln("Hit at ", pos); ++pos; }
   );
 }
The usage can also be: doWhile( pos=text.find("i", pos), pos+1, (writefln("Hit at ", pos), ++pos ) ); Only one char less though :P -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Do we need moderators on this group, or are there just a lot of people around who have more time than things to do. Kill this thread, it's a waste of Oxygen. Steve Teale - No qualifications whatsoever, but been doing it since 1965.
Jul 18 2007
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Steve Teale wrote:
 
 Do we need moderators on this group, or are there just a lot of people around
who have more time than things to do.
 
 Kill this thread, it's a waste of Oxygen.
I don't get it. Are you reading these posts out loud? Anyway don't worry too much. The oxygen's still there, it's just attached to a carbon atom. I think I heard there was some way to get rid of that carbon atom, too. --bb
Jul 18 2007
prev sibling next sibling parent Benjamin Phillips <blackllotus gmail.com> writes:
downs Wrote:

 Taro Kawagishi wrote:
 I think a more natural way to express the logic is to write the code as in
listing 4.
 
     // listing 4
     size_t pos = 0;
     do {
         pos = text.find(pattern, pos);
     } while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n";
         ++pos;
     }
 
 The meaning of
 
     do {
         aa;
     } while (bb) {
         cc;
     }
 
 is
 
     while (true) {
         aa;
         if (not bb) {
             break;
         }
         cc;
     }
void doWhile(void delegate() pre, lazy bool cond, void delegate() post) { while (true) { pre; if (!cond()) break; post; } } // listing 4, modified size_t pos=0; doWhile ({ pos=text.find(pattern, pos); }, pos!=string::npos, { writefln("Pattern found at ", pos); ++pos; }); Not tested, but should work. Have fun!
Being able to create templates that basically act like new keywords is one thing I love about D. I think your solution is better than any of the others posted.
Jul 17 2007
prev sibling next sibling parent Christopher Wright <dhasenan gmail.com> writes:
downs palsat:
 void doWhile(void delegate() pre, lazy bool cond, void delegate() post) {
   while (true) {
     pre;
     if (!cond()) break;
     post;
   }
 }
More simply: void doWhile(void delegate() pre, lazy bool cond, void delegate() post) { for (pre; cond; pre) post; }
Jul 17 2007
prev sibling next sibling parent Charles D Hixson <charleshixsn earthlink.net> writes:
downs wrote:

 void doWhile(void delegate() pre, lazy bool cond, void delegate() post) {
   while (true) {
     pre;
     if (!cond()) break;
     post;
   }
 }
 
 // listing 4, modified
 size_t pos=0;
 doWhile ({
   pos=text.find(pattern, pos);
 }, pos!=string::npos, {
   writefln("Pattern found at ", pos);
   ++pos;
 });
 
 Not tested, but should work.
 Have fun!
I suppose this, or something similar, would work...but UGH!! ugly. I suppose that "De gustibus non disputandum est.", but... care for some okra pie with garlic ice cream?
Jul 21 2007
prev sibling parent janderson <askme me.com> writes:
downs wrote:
 Taro Kawagishi wrote:
 I think a more natural way to express the logic is to write the code 
 as in listing 4.

     // listing 4
     size_t pos = 0;
     do {
         pos = text.find(pattern, pos);
     } while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n";
         ++pos;
     }

 The meaning of

     do {
         aa;
     } while (bb) {
         cc;
     }

 is

     while (true) {
         aa;
         if (not bb) {
             break;
         }
         cc;
     }
void doWhile(void delegate() pre, lazy bool cond, void delegate() post) { while (true) { pre; if (!cond()) break; post; } } // listing 4, modified size_t pos=0; doWhile ({ pos=text.find(pattern, pos); }, pos!=string::npos, { writefln("Pattern found at ", pos); ++pos; }); Not tested, but should work. Have fun!
Nice. Not that I really think we need this new construct however this is what I was thinking. (untested) struct WhileStruct { void delegate() pre; bool delegate() cond; void opCall(void delegate() post) { while (true) { pre(); if (!cond()) break; post(); } } } struct Do { void delegate() pre; static Do opCall(void delegate() pre) //could be a free function { Do d; d.pre = pre; return d; } WhileStruct While(lazy bool cond) { WhileStruct w; w.pre = pre; w.cond = {return cond();}; return w; } } void main() { // Do({...}). //Note that "dot" is the nastiest part // While(...)({...}); //ie Do({pos=text.find(pattern, pos);}). While(pos != string::npos) ({ writefln("Pattern found at ", pos); ++pos; }); } Here are some other forms I think would be possible to code in a library in D. Do({...})(...)({...}); Do[{...}]()[{...}]; Do({...}) (While(...))({...}); while (Do(..., {...})) { }; Do({...}) = While(...) ({}); Do({...}) = (...) = ({}); Do({...}) ~ (...) ~ ({}); Do({...}); //Essentially stores a delegate on the stack While(...) ({...}); The power of D.
Jul 21 2007
prev sibling next sibling parent Manfred Nowak <svv1999 hotmail.com> writes:
Taro Kawagishi wrote

 I think a more natural way to express the logic is to write the
 code as in listing 4. 
 
     // listing 4
     size_t pos = 0;
     do {
         pos = text.find(pattern, pos);
     } while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n";
         ++pos;
     }
 
Where is the problem with using `for'? for( size_t pos= 0 ; ( pos = text.find(pattern, pos), pos != text.length) ; pos++ ) { writefln( "pattern found at %s", pos) ; } -manfred
Jul 17 2007
prev sibling next sibling parent Frank Benoit <keinfarbton googlemail.com> writes:
I also had this situation several times and I really like your suggestion.
Jul 17 2007
prev sibling next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Taro Kawagishi" <tarok acm.org> wrote in message 
news:f7hplb$1ovc$1 digitalmars.com...
 The advantage of the new construct will be seen if you have more complex 
 statements within do and while blocks.
 I believe allowing this extended construct will be smooth since it will 
 not break the existing code.
 I think D language would be a great fit to have this feature because the 
 language seems to be still evolving.
I come across this scenario all the time, and it always strikes me as odd how common the issue is, yet how the language doesn't really provide a simple way to structure it. Agreed.
Jul 17 2007
prev sibling next sibling parent Henning Hasemann <hhasemann web.de> writes:
I agree, too.

The goto thingy looks quite readable, but depending on how long your
loop is it might not be in practice. Also it would be the first time
I'd use goto.

The for-thingy as well as the doWhile mixin (which per se is *really*
cool) loose some expressiveness. Imagine all code blocks would be
longer. How long would you need to understand the meaning compared to
the proposed construct?

Also I dont like making assignment-stuff in the condition-part of a
while or for loop. I once tried it with this and if you have some
not-too-short variable/function/method names you can easily get a
while-condition thats about 5 lines long which is a pain in the eye.

Votes++;

// Henning

-- 
GPG Public Key:
http://keyserver.ganneff.de:11371/pks/lookup?op=get&search=0xDDD6D36D41911851
Fingerprint: 344F 4072 F038 BB9E B35D  E6AB DDD6 D36D 4191 1851
Jul 17 2007
prev sibling next sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Eh... I like it, and I can see where it'd be useful, but I don't think it
justifies the additional complexity. I could go either way though, so... votes
= votes < 0 ? -abs(votes) : abs(votes);

Taro Kawagishi Wrote:

 Hello all,
 
 every once in a while I feel uneasy when I find I can't fit my logic into a
do-while or while loop in a concise way.
 Here is a C++ example:
 
 void
 find_string_occurrences(const string& text, const string& pattern) {
 
     // listing 1
     size_t pos = text.find(pattern, 0);
     while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n";
         ++pos;
         pos = text.find(pattern, pos);
     }
 
 }
 
 The way the code is written might look redundant in calling find() twice, but
I think it is reasonable because you can test the loop condition only after you
run function find() but here you can't use a do-while loop which doesn't allow
you to place other statements after the condition statement.
 
 I can write the same logic as in listing 2 and 3 below, but their meanings
would be less clear than listing 1, because the looping condition is in the if
statement together with the break statement in it, and you need to spot the if
statement in the while body to understand it.
 
     // listing 2
     size_t pos = 0;
     while (true) {
         pos = text.find(pattern, pos);
         if (pos == string::npos) {
             break;
         }
         cout << "pattern found at " << pos << "\n";
         ++pos;
     }
 
     // listing 3
     size_t pos = 0;
     do {
         pos = text.find(pattern, pos);
         if (pos == string::npos) {
             break;
         }
         cout << "pattern found at " << pos << "\n";
         ++pos;
     } while (true);
 
 I think a more natural way to express the logic is to write the code as in
listing 4.
 
     // listing 4
     size_t pos = 0;
     do {
         pos = text.find(pattern, pos);
     } while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n";
         ++pos;
     }
 
 The meaning of
 
     do {
         aa;
     } while (bb) {
         cc;
     }
 
 is
 
     while (true) {
         aa;
         if (not bb) {
             break;
         }
         cc;
     }
 
 and is a natural extension to both of
 
     do {
         aa;
     } while (bb);
 
 and
 
     while (bb) {
         cc;
     }
 
 The current while loop and do-while loop will be specialized forms of this
general do-while loop.
 
 The advantage of the new construct will be seen if you have more complex
statements within do and while blocks.
 I believe allowing this extended construct will be smooth since it will not
break the existing code.
 I think D language would be a great fit to have this feature because the
language seems to be still evolving.
 
Jul 17 2007
prev sibling next sibling parent Ary Manzana <ary esperanto.org.ar> writes:
I like your proposal very much. This pattern is very often, and your 
solution clearly shows the intended behaviour of the code. All the other 
"solutions" are more obscure and more unclear.

I also think extending D with this new construct is realy simple.

Votes++.

Taro Kawagishi escribió:
 Hello all,
 
 every once in a while I feel uneasy when I find I can't fit my logic into a
do-while or while loop in a concise way.
 Here is a C++ example:
 
 void
 find_string_occurrences(const string& text, const string& pattern) {
 
     // listing 1
     size_t pos = text.find(pattern, 0);
     while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n";
         ++pos;
         pos = text.find(pattern, pos);
     }
 
 }
 
 The way the code is written might look redundant in calling find() twice, but
I think it is reasonable because you can test the loop condition only after you
run function find() but here you can't use a do-while loop which doesn't allow
you to place other statements after the condition statement.
 
 I can write the same logic as in listing 2 and 3 below, but their meanings
would be less clear than listing 1, because the looping condition is in the if
statement together with the break statement in it, and you need to spot the if
statement in the while body to understand it.
 
     // listing 2
     size_t pos = 0;
     while (true) {
         pos = text.find(pattern, pos);
         if (pos == string::npos) {
             break;
         }
         cout << "pattern found at " << pos << "\n";
         ++pos;
     }
 
     // listing 3
     size_t pos = 0;
     do {
         pos = text.find(pattern, pos);
         if (pos == string::npos) {
             break;
         }
         cout << "pattern found at " << pos << "\n";
         ++pos;
     } while (true);
 
 I think a more natural way to express the logic is to write the code as in
listing 4.
 
     // listing 4
     size_t pos = 0;
     do {
         pos = text.find(pattern, pos);
     } while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n";
         ++pos;
     }
 
 The meaning of
 
     do {
         aa;
     } while (bb) {
         cc;
     }
 
 is
 
     while (true) {
         aa;
         if (not bb) {
             break;
         }
         cc;
     }
 
 and is a natural extension to both of
 
     do {
         aa;
     } while (bb);
 
 and
 
     while (bb) {
         cc;
     }
 
 The current while loop and do-while loop will be specialized forms of this
general do-while loop.
 
 The advantage of the new construct will be seen if you have more complex
statements within do and while blocks.
 I believe allowing this extended construct will be smooth since it will not
break the existing code.
 I think D language would be a great fit to have this feature because the
language seems to be still evolving.
 
Jul 17 2007
prev sibling next sibling parent reply Joe Gottman <jgottman carolina.rr.com> writes:
Taro Kawagishi wrote:

 
 I think a more natural way to express the logic is to write the code as in
listing 4.
 
     // listing 4
     size_t pos = 0;
     do {
         pos = text.find(pattern, pos);
     } while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n";
         ++pos;
     }
 
 The meaning of
 
     do {
         aa;
     } while (bb) {
         cc;
     }
 
 is
 
     while (true) {
         aa;
         if (not bb) {
             break;
         }
         cc;
     }
 
 and is a natural extension to both of
 
     do {
         aa;
     } while (bb);
 
 and
 
     while (bb) {
         cc;
     }
 
This looks very nice. Does this mean that the entire construct is one scope, so that a variable declared in the aa section is accessible in the bb and cc sections and a variable declared in the bb section is accessible in the cc section? Joe Gottman
Jul 17 2007
parent Taro Kawagishi <tarok acm.org> writes:
Joe Gottman Wrote:

     This looks very nice.  Does this mean that the entire construct is 
 one scope, so that a variable declared in the aa section is accessible 
 in the bb and cc sections and a variable declared in the bb section is 
 accessible in the cc section?
 
 Joe Gottman
Thank you for your comment. Having one scope for the entire construct can be useful, but I think it has to have three separate scopes to be consistent with block rule. Now I realized this could be the biggest inconvenience with this form. -Taro
Jul 18 2007
prev sibling next sibling parent Roberto Mariottini <rmariottini mail.com> writes:
Taro Kawagishi wrote:
 Hello all,
 
 every once in a while I feel uneasy when I find I can't fit my logic into a
do-while or while loop in a concise way.
 Here is a C++ example:
 
 void
 find_string_occurrences(const string& text, const string& pattern) {
 
     // listing 1
     size_t pos = text.find(pattern, 0);
     while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n";
         ++pos;
         pos = text.find(pattern, pos);
     }
 
 }
 
 The way the code is written might look redundant in calling find() twice, but
I think it is reasonable because you can test the loop condition only after you
run function find() but here you can't use a do-while loop which doesn't allow
you to place other statements after the condition statement.
[...]
 I think a more natural way to express the logic is to write the code as in
listing 4.
 
     // listing 4
     size_t pos = 0;
     do {
         pos = text.find(pattern, pos);
     } while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n";
         ++pos;
     }
 
 The meaning of
 
     do {
         aa;
     } while (bb) {
         cc;
     }
 
 is
 
     while (true) {
         aa;
         if (not bb) {
             break;
         }
         cc;
     }
 
 and is a natural extension to both of
 
     do {
         aa;
     } while (bb);
 
 and
 
     while (bb) {
         cc;
     }
 
 The current while loop and do-while loop will be specialized forms of this
general do-while loop.
I agree with you, and I see the need for such a construct. But this was already discussed some year ago, and Walter didn't like the idea. Ciao
Jul 18 2007
prev sibling next sibling parent Regan Heath <regan netmail.co.nz> writes:
You could also use inline functions eg.

{

   T p;

   T complex_pre()
   {
   }

   T complex_post()
   {
   }

   for( p = complex_pre(); p != null; p = complex_post())
   {
     ..body..
   }

}

Regan
Jul 18 2007
prev sibling next sibling parent Taro Kawagishi <tarok acm.org> writes:
Don Clugston Wrote:

 Forth has this construct in the form of a BEGIN ... WHILE ... REPEAT loop. I 
 don't think I've seen it elsewhere, though. Uses for it come up fairly 
 frequently in my experience, but as others have mentioned, the for(;;) { aa;
if 
 (cond) break; bb; } idiom isn't too bad.
 Walter uses 'goto' more than any other programmer I've ever seen. Search
through 
 Phobos and the DMD front-end for 'goto', and see how many could be replaced by 
 your do-while loop. Is it a significant fraction of the total?
It is great to know forth has a similar construct. I agree with you that many types of loops can't be written the way I proposed. -Taro
Jul 18 2007
prev sibling next sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Taro Kawagishi wrote:
 Hello all,
 
 every once in a while I feel uneasy when I find I can't fit my logic into a
do-while or while loop in a concise way.
 Here is a C++ example:
 
 void
 find_string_occurrences(const string& text, const string& pattern) {
 
     // listing 1
     size_t pos = text.find(pattern, 0);
     while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n";
         ++pos;
         pos = text.find(pattern, pos);
     }
 
 }
 
 The way the code is written might look redundant in calling find() twice, but
I think it is reasonable because you can test the loop condition only after you
run function find() but here you can't use a do-while loop which doesn't allow
you to place other statements after the condition statement.
 
 I can write the same logic as in listing 2 and 3 below, but their meanings
would be less clear than listing 1, because the looping condition is in the if
statement together with the break statement in it, and you need to spot the if
statement in the while body to understand it.
 
     // listing 2
     size_t pos = 0;
     while (true) {
         pos = text.find(pattern, pos);
         if (pos == string::npos) {
             break;
         }
         cout << "pattern found at " << pos << "\n";
         ++pos;
     }
 
     // listing 3
     size_t pos = 0;
     do {
         pos = text.find(pattern, pos);
         if (pos == string::npos) {
             break;
         }
         cout << "pattern found at " << pos << "\n";
         ++pos;
     } while (true);
 
 I think a more natural way to express the logic is to write the code as in
listing 4.
 
     // listing 4
     size_t pos = 0;
     do {
         pos = text.find(pattern, pos);
     } while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n";
         ++pos;
     }
 
 The meaning of
 
     do {
         aa;
     } while (bb) {
         cc;
     }
 
 is
 
     while (true) {
         aa;
         if (not bb) {
             break;
         }
         cc;
     }
 
 and is a natural extension to both of
 
     do {
         aa;
     } while (bb);
 
 and
 
     while (bb) {
         cc;
     }
 
 The current while loop and do-while loop will be specialized forms of this
general do-while loop.
 
 The advantage of the new construct will be seen if you have more complex
statements within do and while blocks.
 I believe allowing this extended construct will be smooth since it will not
break the existing code.
 I think D language would be a great fit to have this feature because the
language seems to be still evolving.
 
Argh no! Another foreach_reverse crappy redundant construct. There are at least 3 alternatives in which *IMO* any of them is better than adding a language construct, so votes -= 3 ! Tomas Olsen's: while(true) { aa... if (!cond...) break; bb... } Gregor's: size_t pos = 0; while ((pos = text.find(pattern, pos)) != string::npos) { ... } down's: doWhile( pos = text.find("i", pos), pos + 1, { writefln("Hit at ", pos); ++pos; } ); -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Jul 18 2007
parent Manfred Nowak <svv1999 hotmail.com> writes:
Bruno Medeiros wrote

 Argh no! Another
[...]
 redundant construct.
"No" confirmed, but its not redundant: it will break existing code. I use blocks to group statements: { // computing this and that ... } and in conjunction with a block no statement needs the `;'- delimiter!!! I.e.
     do {
         aa;
     } while (bb) {
         cc;
     }
is legal code already, but `cc;' is executed only once after the loop ended. -manfred
Jul 18 2007
prev sibling next sibling parent "Stewart Gordon" <smjg_1998 yahoo.com> writes:
"Taro Kawagishi" <tarok acm.org> wrote in message 
news:f7hplb$1ovc$1 digitalmars.com...
<snip>
 I can write the same logic as in listing 2 and 3 below, but their meanings 
 would be less clear than listing 1, because the looping condition is in 
 the if statement together with the break statement in it, and you need to 
 spot the if statement in the while body to understand it.
<snip> On seeing a while (true), I think it goes without saying that you need to look for a break or return statement somewhere to find the terminating condition. BTW here are two other ways of doing your particular case: // listing 5 size_t pos = 0; while ((pos = text.find(pattern, 0)) != string::npos) { cout << "pattern found at " << pos << "\n"; ++pos; } // listing 6 for (size_t pos = 0; (pos = text.find(pattern, 0)) != string::npos; ++pos) { cout << "pattern found at " << pos << "\n"; } but I realise this is no use in the more general case when you've got more to do in the portion before the break.
 I think a more natural way to express the logic is to write the code as in 
 listing 4.

    // listing 4
    size_t pos = 0;
    do {
        pos = text.find(pattern, pos);
    } while (pos != string::npos) {
        cout << "pattern found at " << pos << "\n";
        ++pos;
    }
<snip> I'm not sure I like this notation. There are always going to be people who prefer to put curly brackets on a line of their own. And then, given a snippet of code ... } while (cond) { ... it'll be necessary to scroll, possibly through several screens of code, just to find out whether the block above the while is part of the loop as well. Moreover, I don't know if it's a common pitfall to write do { ... } (with no while clause) intending an infinite loop (or one that must be broken out of). But should somebody fall into this trap and follow it immediately with a while loop, it would take on a whole new meaning.
 The current while loop and do-while loop will be specialized forms of this 
 general do-while loop.

 The advantage of the new construct will be seen if you have more complex 
 statements within do and while blocks.
 I believe allowing this extended construct will be smooth since it will 
 not break the existing code.
<snip> I'm still not sure it gains anything practically over the if-break method. Moreover, what if you want multiple terminating conditions at different points in the loop? You can put any number of breaks in a loop; your idea OTOH doesn't easily extend to multiple exit points. (For the record, Beta Basic on the ZX Spectrum had an "EXIT IF" statement, really the equivalent of if-break though it also looked a bit like your idea, especially as the automatic indentation would show that particular statement at the same level as the DO and LOOP. If you like, you _could_ outdent your if-break statements to achieve the same effect....) Stewart.
Jul 19 2007
prev sibling parent reply Charles D Hixson <charleshixsn earthlink.net> writes:
Taro Kawagishi wrote:
 Hello all,
 
 every once in a while I feel uneasy when I find I can't fit my logic into a
do-while or while loop in a concise way.
 Here is a C++ example:
 
 void
 find_string_occurrences(const string& text, const string& pattern) {
 
     // listing 1
     size_t pos = text.find(pattern, 0);
     while (pos != string::npos) {
         cout << "pattern found at " << pos << "\n";
         ++pos;
         pos = text.find(pattern, pos);
     }
 
 }
 ...
to me the best solution would appear something along the lines of: loop { size_t pos = text.find(pattern, 0); // declare a new pos on each iteration?? if (pos == string::npos) break; cout << "pattern found at " << pos << "\n"; // tango is not standard D, but I think I understand // what you are doing ++pos; pos = text.find(pattern, pos); } I'd prefer the Ada-esque exit when (pos == string::npos); but that means introducing new key words (more than just "loop"). OTOH, I guess there's nothing wrong with having an un-parameterized "do" instead of loop, as in: do { ... do stuff ... when(condition) break; } in the case the "when" is semantically the same as an if, but it clarifies what's going on. One could limit it's use to "only usable within a do loop". But I would prefer the syntax of either: exit when (condition); or break when (condition); as I feel that these are clearer.
Jul 21 2007
parent reply "Rioshin an'Harthen" <rharth75 hotmail.com> writes:
"Charles D Hixson" <charleshixsn earthlink.net> kirjoitti viestissä 
news:f7t5ki$1mn0$1 digitalmars.com...
 I'd prefer the Ada-esque
      exit when (pos == string::npos);
 but that means introducing new key words (more than just "loop").  OTOH, I 
 guess there's nothing wrong with having an un-parameterized "do" instead 
 of loop, as in:
    do
    {  ... do stuff ...
       when(condition) break;
    }
 in the case the "when" is semantically the same as an if, but it clarifies 
 what's going on.  One could limit it's use to "only usable within a do 
 loop".  But I would prefer the syntax of either:
       exit when (condition);
 or
       break when (condition);
 as I feel that these are clearer.
I'd say no to a new keyword just for this. However, a syntax like break if (condition); would, in my opinion, be better than if (condition) break;
Jul 22 2007
parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Rioshin an'Harthen wrote:
 "Charles D Hixson" <charleshixsn earthlink.net> kirjoitti viestissä 
 news:f7t5ki$1mn0$1 digitalmars.com...
 I'd prefer the Ada-esque
      exit when (pos == string::npos);
 but that means introducing new key words (more than just "loop").  
 OTOH, I guess there's nothing wrong with having an un-parameterized 
 "do" instead of loop, as in:
    do
    {  ... do stuff ...
       when(condition) break;
    }
 in the case the "when" is semantically the same as an if, but it 
 clarifies what's going on.  One could limit it's use to "only usable 
 within a do loop".  But I would prefer the syntax of either:
       exit when (condition);
 or
       break when (condition);
 as I feel that these are clearer.
I'd say no to a new keyword just for this. However, a syntax like break if (condition); would, in my opinion, be better than if (condition) break;
I sit back and watch as D slowly evolves into Ruby... ;) -- Chris Nicholson-Sauls
Jul 22 2007