www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - while(...){ ... }else ...

reply "Jens Bauer" <doctor who.no> writes:
I've sometimes wished for a while ... else combination in C.
-But I never got around to proposing my suggestion to whoever or 
whatever committee is in charge of the C language.

But since D is a language that has much more freedom regarding 
implementation, I'd like to suggest it here. :)

This is my usual code:
if(c >= '0' && c <= '9')
{
     /* number */
     while(c >= '0' && c <= '9')
     {
         c = *s++;
         ... do something with c ...
     }
}
else if((c >= 'A' && c <= 'Z') || (c >='a' && c <= 'z') || c == 
'_')
{
     /* token */
     while((c >= 'A' && c <= 'Z') || (c >='a' && c <= 'z') || c == 
'_')
     {
         c = *s++;
     }
}
else if(debug)
{
     /* error */
}

... The arguments for 'if' and 'while' are the same, and the 
initial test could be reduced to a single test instead of 
multiple tests...

while(c >= '0' && c <= '9')
{
     /* number */
     c = *s++;
     ... do something with c ...
}
else while((c >= 'A' && c <= 'Z') || (c >='a' && c <= 'z') || c 
== '_')
{
     /* token */
     c = *s++;
}
else if(debug)
{
     /* error */
}

... Ah, much more readable.
This makes it possible to repeat actions, in case a statement is 
true, generalizing the while statement slightly.

Thus... If we for instance enter the first while(...), then we 
will not enter any of the 'else' statements.
Jan 18 2015
next sibling parent reply "MattCoder" <stop spam.com> writes:
On Sunday, 18 January 2015 at 15:52:24 UTC, Jens Bauer wrote:
 ... Ah, much more readable.
Maybe I misunderstood your question, but what you think about this way: while(1){ if(c >= '0' && c <= '9') { /* number */ c = *s++; ... do something with c ... } else if ((c >= 'A' && c <= 'Z') || (c >='a' && c <= 'z') || c == '_') { /* token */ c = *s++; } else if(debug) { /* error */ break; } } Matheus.
Jan 18 2015
parent reply "Jens Bauer" <doctor who.no> writes:
On Sunday, 18 January 2015 at 16:03:24 UTC, MattCoder wrote:
 On Sunday, 18 January 2015 at 15:52:24 UTC, Jens Bauer wrote:

 Maybe I misunderstood your question, but what you think about 
 this way:
... It's close, but the result would be different. The while is a combined if+while, where the first test of the while would be the 'if'. In the while(1) example, the character 'c' would perhaps be a number the first time. On the second iteration, the character would be allowed to be a letter. However, in the original 'proposal', the loops would be 'tighter'; the kind would be found first, and then the 'width' of that kind second, and when the end of the kind was reached, the while-block would be exited. So in other words: First check: Is it a number; if so, get the entire number... If not, try the second check: is it a token; if so, get the entire token, otherwise let us know that it's something unknown (but only if we're debugging).
Jan 18 2015
parent "MattCoder" <stop spam.com> writes:
On Sunday, 18 January 2015 at 22:54:16 UTC, Jens Bauer wrote:
 On Sunday, 18 January 2015 at 16:03:24 UTC, MattCoder wrote:
 On Sunday, 18 January 2015 at 15:52:24 UTC, Jens Bauer wrote:
... First check: Is it a number; if so, get the entire number... If not, try the second check: is it a token; if so, get the entire token, otherwise let us know that it's something unknown (but only if we're debugging).
Alright I see the purpose about: "while(){}else(){}", but unfortunately D doesn't have this. Anyway looking at your first post, I'd like to suggest a way to improve your code: /* Create a "type check" function/method... you named it returning a defined type */ import std.string; type checkType(sometype s){ if(isNumeric(s)){ return TYPE_NUMBER; } // Check using regex for A..Z, a..z and '_' return TYPE_TOKEN; return TYPE_UNDEFINED; } // And then somewhere in your code you could do this: ... { switch(checkType(s)){ case TYPE_NUMBER : doNumberThing(s); break; case TYPE_TOKEN : doTokenThing(s); break; default : checkDebug(); } } It's not what you proposed earlier, but I think it can make things easier. Matheus.
Jan 18 2015
prev sibling parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
Unfortunately, this would break existing code:

     if(some_condition)
         while(some_other_condition) {
             // ...
         }
     else
         // ...

Currently, the `else` branch belongs to the `if`; with your 
proposal, it would belong to the `while`.

An `else` always attaches to the closest construct where it can 
be accepted; AFAICS, this cannot be changed without making the 
language grammar context-sensitive (it would require parsing 
`while` inside an `if` differently from other `while`s).
Jan 18 2015
next sibling parent reply "Jens Bauer" <doctor who.no> writes:
On Sunday, 18 January 2015 at 18:16:47 UTC, Marc Schütz wrote:
 Unfortunately, this would break existing code:
That is absolutely correct. Good catch. I did not think of that particular case. However... What if the 'else', which "belongs" to while, is named differently, for instance ... while(expression1) { } otherwise if(expression2) { } I know otherwise is a longer word, but it would not clash with existing code.
Jan 18 2015
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdan.org> writes:
"Jens Bauer" <doctor who.no> wrote:
 On Sunday, 18 January 2015 at 18:16:47 UTC, Marc Schütz wrote:
 Unfortunately, this would break existing code:
That is absolutely correct. Good catch. I did not think of that particular case. However... What if the 'else', which "belongs" to while, is named differently, for instance ... while(expression1) { } otherwise if(expression2) { } I know otherwise is a longer word, but it would not clash with existing code.
The short answer is we are not considering such a feature. Thanks.
Jan 18 2015
prev sibling next sibling parent reply ketmar via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Sun, 18 Jan 2015 22:56:23 +0000
Jens Bauer via Digitalmars-d <digitalmars-d puremagic.com> wrote:

 On Sunday, 18 January 2015 at 18:16:47 UTC, Marc Sch=C3=BCtz wrote:
 Unfortunately, this would break existing code:
=20 That is absolutely correct. Good catch. I did not think of that=20 particular case. =20 However... What if the 'else', which "belongs" to while, is named=20 differently, for instance ... =20 while(expression1) { } otherwise if(expression2) { } =20 I know otherwise is a longer word, but it would not clash with=20 existing code.
it will introduce a new keyword, and it will break any code which using "otherwise" as identifier. as far as i can tell this (introducing new keyword) is one of the hardest thing to do, 'cause Walter will reject it without second thought (and he will be perfectly right).
Jan 18 2015
parent reply "Jens Bauer" <doctor who.no> writes:
On Sunday, 18 January 2015 at 23:06:27 UTC, ketmar via 
Digitalmars-d wrote:
 it will introduce a new keyword, and it will break any code 
 which using
 "otherwise" as identifier. as far as i can tell this 
 (introducing new
 keyword) is one of the hardest thing to do, 'cause Walter will 
 reject
 it without second thought (and he will be perfectly right).
That's OK with me. I'm not discouraged. Now I no longer have to go and think about this. I'd rather show someone the idea and getting it rejected, than keeping it to myself and often regret that I never said anything. -A rejection will not stop me from making another proposal, though - in fact, I do have one more. ;)
Jan 18 2015
parent ketmar via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Sun, 18 Jan 2015 23:20:43 +0000
Jens Bauer via Digitalmars-d <digitalmars-d puremagic.com> wrote:

 -A rejection will not stop me from making another proposal,=20
 though - in fact, I do have one more. ;)
sure, you're welcome! this one is not so good, but another one may be brilliant. and even if it will not be so brilliant... you always can make a third one. and fourth. and so on. ;-)
Jan 18 2015
prev sibling parent reply "Jens Bauer" <doctor who.no> writes:
I'd like to give an example on a different use of the same 
feature:

while(length--)
{
     *d++ = *s++;
}
if(length == -1)  /* the programmer will need to know the value 
of length here. */
{
     /* handle case where length was exactly 0, it's now -1 */
}

would become:

while(length--)
{
     *d++ = *s++;
}
otherwise
{
     /* handle case where length was exactly 0, it's now -1 */
}

---
A pseudo-assembly language version of a normal while-loop:

     bra wstart   /* this usually cost (something like) a 
clock-cycle to start */
while:
     copy.b s+,d+
wstart:
     sub length,#1
     bcc while
  wend:

---
Different version of the above:

     sub length,#1
     bcs wend
while:
     copy.b s+,d+
     sub length,#1
     bcc while
wend:
---
A pseudo-assembly language version of the 'otherwise' while-loop:
     sub  length,#1
     bcs  otherwise
while:
     copy.b s+,d+
     sub length,#1
     bcc while
     bra wend
otherwise:
     /* handle zero-length */
wend:

-These are not real good examples, though. However, they do show 
that the compiler would know that it can safely optimize the 
expression-test, and almost for free get the 'otherwise', which 
would cost only little extra CPU-time.
Jan 18 2015
parent ketmar via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Sun, 18 Jan 2015 23:16:11 +0000
Jens Bauer via Digitalmars-d <digitalmars-d puremagic.com> wrote:

 I'd like to give an example on a different use of the same=20
 feature:
=20
 while(length--)
 {
      *d++ =3D *s++;
 }
 if(length =3D=3D -1)  /* the programmer will need to know the value=20
 of length here. */
 {
      /* handle case where length was exactly 0, it's now -1 */
 }
=20
 would become:
=20
 while(length--)
 {
      *d++ =3D *s++;
 }
 otherwise
 {
      /* handle case where length was exactly 0, it's now -1 */
 }
=20
first sample is just a bad code, but second sample is a kind of cypher. there is no sense in doing such microoptimisations, as decent modern compiler is able to do dataflow analysis and cse. and both samples are bad, 'cause they violates the rule "check first, then process". did you profile your code and found that such loops are real bottlenecks? i bet they aren't. yet they less readable than clearly spelled preconditions. this is microoptimisation in the sake of microoptimisation, it wins almost nothing and hurts code readability. all in all it's one of that things that looks nice, but makes more problems than they are able to solve. that's why language design is hard: nicely looking features can have many unforseen consequences. ;-)
Jan 18 2015
prev sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 18 January 2015 at 18:16:47 UTC, Marc Schütz wrote:
 Unfortunately, this would break existing code:

     if(some_condition)
         while(some_other_condition) {
             // ...
         }
     else
         // ...

 Currently, the `else` branch belongs to the `if`; with your 
 proposal, it would belong to the `while`.

 An `else` always attaches to the closest construct where it can 
 be accepted; AFAICS, this cannot be changed without making the 
 language grammar context-sensitive (it would require parsing 
 `while` inside an `if` differently from other `while`s).
Compiler have simplification of CFG passes that makes this feature irrelevant in practice.
Jan 18 2015