www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Ideas regarding flow control and loops

reply =?ISO-8859-1?Q?Marco_Aur=e9lio?= <thecoreh gmail.com> writes:
Hello! I've been following the development of the D programming language for
some time (around 1 year), and I have to say it keeps looking better.

I don't know if these have been proposed before, but I would like to make two
suggestions regarding flow control and loops:

1- if behavior on "with" statement:

On the current specification of D, if you want to check if a class can be
casted to a subclass, and do something with it, you have to do something like:

if (cast(Foo)bar)
    with(cast(Foo)bar)
    {
        DoSomething();
    }

While that works, it makes you have to write the same thing twice, and unless
some compiler optimization kicks in (not sure if compilers check for that), the
cast will have to be done twice. (and since it performs a runtime check, it
will take some time) You could also use a temporary variable, but that wouldn't
be so elegant.

My idea is to make the with statement also behave like an if statement, so the
above code could be rewritten as only:

with(cast(Foo)bar)
{
    DoSomething();
}

There's the possibility this would make existing code slower, due to
unnecessary checks for null (if you're not typecasting and are sure it's not
null), so another possibility would be making the syntax like:

if with(cast(Foo)bar)
{
    DoSomething();
}

So the default "with" behavior would be preserved. Note that since it behaves
like an if, you could add an else at the end, like:


if with(cast(Foo)bar)
{
    DoSomething();
} else {
    writeln("Not possible!");
}


2 - for .. finally, while .. finally:

This would allow having something like:

while(someCondition)
{
    DoSomething();
} finally {
    DoOtherThing();
}

The "finally" block would be called at the end of the repetition, only if no
"break" was used. This may not seem useful at first, but I think can reduce the
number of flags needed to implement various algorithms, making the code faster
and more elegant. I'm not sure if this is already possible with scope guards.

That's it.. What do you think?
Nov 03 2007
next sibling parent reply downs <default_357-line yahoo.de> writes:
Marco Aurélio wrote:
 Hello! I've been following the development of the D programming language for
some time (around 1 year), and I have to say it keeps looking better.
 
 I don't know if these have been proposed before, but I would like to make two
suggestions regarding flow control and loops:
 
 1- if behavior on "with" statement:
I used to have the same problem - I even wrote an ifIs template to get around the repetition. Then somebody clued me in to this: if (auto foo=cast(Whee) bar) { /* use foo* } ISN'T IT NEAT? <3 D.
 2 - for .. finally, while .. finally:
 
 This would allow having something like:
 
 while(someCondition)
 {
     DoSomething();
 } finally {
     DoOtherThing();
 }
 
 The "finally" block would be called at the end of the repetition, only if no
"break" was used. This may not seem useful at first, but I think can reduce the
number of flags needed to implement various algorithms, making the code faster
and more elegant. I'm not sure if this is already possible with scope guards.
 
I like that. :) vote +1 --downs
Nov 03 2007
next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
downs wrote:
 Marco Aurélio wrote:
 Hello! I've been following the development of the D programming language for
some time (around 1 year), and I have to say it keeps looking better.

 I don't know if these have been proposed before, but I would like to make two
suggestions regarding flow control and loops:

 1- if behavior on "with" statement:
I used to have the same problem - I even wrote an ifIs template to get around the repetition. Then somebody clued me in to this: if (auto foo=cast(Whee) bar) { /* use foo* } ISN'T IT NEAT? <3 D.
Oh hell yeah.
 2 - for .. finally, while .. finally:

 This would allow having something like:

 while(someCondition)
 {
     DoSomething();
 } finally {
     DoOtherThing();
 }

 The "finally" block would be called at the end of the repetition, only if no
"break" was used. This may not seem useful at first, but I think can reduce the
number of flags needed to implement various algorithms, making the code faster
and more elegant. I'm not sure if this is already possible with scope guards.
I like that. :) vote +1 --downs
else would also be nice. foreach( foo ; bar ) DoSomethingWith(foo); finally DoSomethingAfterwards(); else DoSomethingElseSinceBarIsEmpty(); But maybe that's just me. -- Daniel
Nov 03 2007
next sibling parent reply =?ISO-8859-1?Q?Marco_Aur=e9lio?= <thecoreh gmail.com> writes:
Daniel Keep Wrote:
 else would also be nice.
This would be specially usefull for implementing collisions on 2D games with bitmap-based coldefs, something along the lines of: while(object.isCollidingWithGround()) { object.moveUp(); } finally { object.stop(); } else { object.applyGravity(); } While the object is colliding with the ground, move it up... Then stop it.. and if he wasn't colliding with the ground in the first place, apply gravity.
Nov 03 2007
next sibling parent reply downs <default_357-line yahoo.de> writes:
Marco Aurélio wrote:
 Daniel Keep Wrote:
 else would also be nice.
This would be specially usefull for implementing collisions on 2D games with bitmap-based coldefs, something along the lines of: while(object.isCollidingWithGround()) { object.moveUp(); } finally { object.stop(); } else { object.applyGravity(); } While the object is colliding with the ground, move it up... Then stop it.. and if he wasn't colliding with the ground in the first place, apply gravity.
Well, technically ... --downs PS: module test17; import std.stdio; void extwhile(lazy bool cond, void delegate() Body, void delegate() Finally, void delegate() Else) { if (!cond()) Else(); else { do Body(); while (cond()); Finally(); } } void main() { bool colliding=true; int counter=0; extwhile(colliding, { writefln("Still colliding"); counter++; if (counter==3) colliding=false; }, { writefln("Done colliding"); }, { writefln("Never collided"); } ); }
Nov 03 2007
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
downs Wrote:

 PS:
 module test17;
 import std.stdio;
 
 void extwhile(lazy bool cond, void delegate() Body, void delegate()
 Finally, void delegate() Else) {
   if (!cond()) Else();
   else {
     do Body(); while (cond());
     Finally();
   }
 }
 
 void main() {
   bool colliding=true;
   int counter=0;
   extwhile(colliding,
     { writefln("Still colliding"); counter++; if (counter==3)
 colliding=false; },
     { writefln("Done colliding"); },
     { writefln("Never collided"); }
   );
 }
Heh, closures are already spreading their intoxicating power.
Nov 03 2007
next sibling parent =?ISO-8859-1?Q?Marco_Aur=e9lio?= <thecoreh gmail.com> writes:
Robert Fraser Wrote:

 downs Wrote:
 
 PS:
 module test17;
 import std.stdio;
 
 void extwhile(lazy bool cond, void delegate() Body, void delegate()
 Finally, void delegate() Else) {
   if (!cond()) Else();
   else {
     do Body(); while (cond());
     Finally();
   }
 }
 
 void main() {
   bool colliding=true;
   int counter=0;
   extwhile(colliding,
     { writefln("Still colliding"); counter++; if (counter==3)
 colliding=false; },
     { writefln("Done colliding"); },
     { writefln("Never collided"); }
   );
 }
Heh, closures are already spreading their intoxicating power.
Wow. I didn't know you could do that, even with closures.
Nov 03 2007
prev sibling parent downs <default_357-line yahoo.de> writes:
Robert Fraser wrote:
 downs Wrote:
 
 PS:
 module test17;
 import std.stdio;

 void extwhile(lazy bool cond, void delegate() Body, void delegate()
 Finally, void delegate() Else) {
   if (!cond()) Else();
   else {
     do Body(); while (cond());
     Finally();
   }
 }

 void main() {
   bool colliding=true;
   int counter=0;
   extwhile(colliding,
     { writefln("Still colliding"); counter++; if (counter==3)
 colliding=false; },
     { writefln("Done colliding"); },
     { writefln("Never collided"); }
   );
 }
Heh, closures are already spreading their intoxicating power.
It doesn't actually use closures. Completely D 1.0 :) Those { } things are short-hand for () { }, i.e. completely normal delegate literals. --downs
Nov 03 2007
prev sibling parent Bruce Adams <tortoise_74 yeah.who.co.uk> writes:
Marco Aurélio Wrote:

 Daniel Keep Wrote:
 else would also be nice.
This would be specially usefull for implementing collisions on 2D games with bitmap-based coldefs, something along the lines of: while(object.isCollidingWithGround()) { object.moveUp(); } finally { object.stop(); } else { object.applyGravity(); } While the object is colliding with the ground, move it up... Then >stop it.. and if he wasn't colliding with the ground in the first place, >apply gravity.
What's wrong with: if (!object.isCollidingWithGround()) object.applyGravity(); else do { object.moveUp(); } while (object.isCollidingWithGround()); object.stop(); You've got one extra condition to write but its not really a big deal.
Nov 04 2007
prev sibling parent reply BCS <ao pathlink.com> writes:
Reply to Daniel,

 downs wrote:
 
 Marco Aurélio wrote:
 
 2 - for .. finally, while .. finally:
 
 This would allow having something like:
 
 while(someCondition)
 {
 DoSomething();
 } finally {
 DoOtherThing();
 }
 The "finally" block would be called at the end of the repetition,
 only if no "break" was used. This may not seem useful at first, but
 I think can reduce the number of flags needed to implement various
 algorithms, making the code faster and more elegant. I'm not sure if
 this is already possible with scope guards.
 
I like that. :) vote +1 --downs
else would also be nice. foreach( foo ; bar ) DoSomethingWith(foo); finally DoSomethingAfterwards(); else DoSomethingElseSinceBarIsEmpty(); But maybe that's just me. -- Daniel
I'd rather an extension of the scope syntax while(cond) { scope(last) DoOnCondFailed(); scope(break) DoOnBreak(); // or any explicet quit scope(skip) DoIfCondNeverPasses(); scope(first) goto SkipSomeStuff; ... }
Nov 03 2007
parent reply Bruce Adams <tortoise_74 yeah.who.co.uk> writes:
BCS Wrote:

 Reply to Daniel,
 
 downs wrote:
 
 Marco Aurélio wrote:
 
 2 - for .. finally, while .. finally:
 
 This would allow having something like:
 
 while(someCondition)
 {
 DoSomething();
 } finally {
 DoOtherThing();
 }
 The "finally" block would be called at the end of the repetition,
 only if no "break" was used. This may not seem useful at first, but
 I think can reduce the number of flags needed to implement various
 algorithms, making the code faster and more elegant. I'm not sure if
 this is already possible with scope guards.
 
I like that. :) vote +1 --downs
else would also be nice. foreach( foo ; bar ) DoSomethingWith(foo); finally DoSomethingAfterwards(); else DoSomethingElseSinceBarIsEmpty(); But maybe that's just me. -- Daniel
I'd rather an extension of the scope syntax while(cond) { scope(last) DoOnCondFailed(); scope(break) DoOnBreak(); // or any explicet quit scope(skip) DoIfCondNeverPasses(); scope(first) goto SkipSomeStuff; ... }
Lets take these one at a time:- scope(last): - totally useless assuming I understood the meaning while(cond) { } DoOnCondFailed(); scope(skip): - saves you one conditional - not very useful if (!cond) DoIfCondNeverPasses(); else do { ... } while(cond); scope(break): - saves you a function call or two. while(cond) { ... if (cond2) DoOnBreak(); break; ... if (cond3) DoOnBreak(); break; ... } scope(first): if (cond) { DoFirstTimeOnly(); } while(cond) { ... } goto is evil so you want the opposite too scope(notonfirst): while(cond) { static bool firstTime = false; if (firstTime==false) { firstTime = true; body1(); } body2(); } For this case there is slight justification for something. but that something is a notfirst() functor. class notfirst { private: bool first; delegate doOnFirst; delegate doOnSubsequent; public: notfirst(delegate doOnFirst_, delegate doOnSubsequent_): first(true) doOnFirst(doOnFirst_), doOnSubsequent(doOnSubsequent_) {} void run() { if (first) { doOnFirst(); first = false; } else doOnSubsequent(); } }; while(cond) { doOnFirst(body1(); body2()); } What is this equivalent to in the worst case scenario that you need all four? if (!cond) DoIfCondNeverPasses(); else { DoFirstTimeOnly(); do { doOnFirst(body1(); { ... if (cond2) DoOnBreak(); break; ... if (cond3) DoOnBreak(); break; ... } } while(cond); } DoOnCondFailed(); On balance this doesn't seem like a necessary or really useful syntax improvement to me. Regards, Bruce. to me.
Nov 04 2007
parent reply BCS <ao pathlink.com> writes:
Reply to Bruce,

 BCS Wrote:
 
 I'd rather an extension of the scope syntax
 
 while(cond)
 {
 scope(last) DoOnCondFailed();
 scope(break) DoOnBreak(); // or any explicet quit
 scope(skip) DoIfCondNeverPasses();
 scope(first) goto SkipSomeStuff;
 ...
 }
Lets take these one at a time:- scope(last): - totally useless assuming I understood the meaning while(cond) { } DoOnCondFailed();
for(int i = 5; i>0 i--) { scope(last) ThisNeverRuns(); break; }
 scope(skip):  - saves you one conditional - not very useful
 
 if (!cond)
 DoIfCondNeverPasses();
 else do
 {
 ...
 }
 while(cond);
 
mine looks better (IMHO)
 scope(break): - saves you a function call or two.
 
 while(cond)
 {
 ...
 if (cond2) DoOnBreak(); break;
 ...
 if (cond3) DoOnBreak(); break;
 ...
 }
you prove half of my point and don't address the other half while(cond) { ... if (cond2) DoOnBreak(); break; ... // this never runs if (cond3) DoOnBreak(); break; ... } If you didn't get it correct in this case, what are the chances of making an error in a more complicated case The other part is that it is very easy to forget to add the DoOnBreak to one of the breaks (you try finding them all in old code) or adding it to every new one (Now what needs to be done on break this time). Also, it will work with mixin(string) when you can't get to the string.
 scope(first):
 
 if (cond)
 {
 DoFirstTimeOnly();
 }
 while(cond)
 {
 ...
 }
 goto is evil so you want the opposite too
 
 scope(notonfirst):
 
good idea.
 while(cond)
 {
 static bool firstTime = false;
 if (firstTime==false) { firstTime = true; body1(); }
 body2();
 }
 For this case there is slight justification for something. but that
 something is a notfirst() functor.
 
 class notfirst
 {
 private:
 bool first;
 delegate doOnFirst;
 delegate doOnSubsequent;
 public:
 notfirst(delegate doOnFirst_,
 delegate doOnSubsequent_):
 first(true)
 doOnFirst(doOnFirst_),
 doOnSubsequent(doOnSubsequent_)
 {}
 void run() {
 if (first)
 {
 doOnFirst();
 first = false;
 }
 else doOnSubsequent();
 }
 };
 while(cond)
 {
 doOnFirst(body1(); body2());
 }
My eyes!!! I can't think of anything good to say about that solution.
 What is this equivalent to in the worst case scenario that you need
 all four?
 
 if (!cond)
 DoIfCondNeverPasses();
 else
 {
 DoFirstTimeOnly();
 do
 {
 doOnFirst(body1();
 {
 ...
 if (cond2) DoOnBreak(); break;
 ...
 if (cond3) DoOnBreak(); break;
 ...
 }
 }
 while(cond);
 }
 DoOnCondFailed();
 
 On balance this doesn't seem like a necessary or really useful syntax
 improvement to me.
 
the same can be said for scope(failure/success/exit). It's all sugar. I think the scope(*) solution looks better and is easier to read an maintain in _all_ the cases you list. In all these cases the compiler can trivially implement them with copy/paste and by rearranging jumps.
 Regards,
 
 Bruce.
 to me.
Nov 04 2007
parent reply Bruce Adams <tortoise_74 yeah.who.co.uk> writes:
BCS Wrote:

 Reply to Bruce,
 
 BCS Wrote:
 
 I'd rather an extension of the scope syntax
 
 while(cond)
 {
 scope(last) DoOnCondFailed();
 scope(break) DoOnBreak(); // or any explicet quit
 scope(skip) DoIfCondNeverPasses();
 scope(first) goto SkipSomeStuff;
 ...
 }
Lets take these one at a time:- scope(last): - totally useless assuming I understood the meaning while(cond) { } DoOnCondFailed();
for(int i = 5; i>0 i--) { scope(last) ThisNeverRuns(); break; }
Right. So what you really want is something that runs when the scope ends naturally but not on a break. for(int i=5;i>0;i--) { ... break; } if (i<=0) ThisNeverRuns();
 scope(skip):  - saves you one conditional - not very useful
 
 if (!cond)
 DoIfCondNeverPasses();
 else do
 {
 ...
 }
 while(cond);
 
mine looks better (IMHO)
It doesn't justify a syntax change (IMHO)
 scope(break): - saves you a function call or two.
 
 while(cond)
 {
 ...
 if (cond2) DoOnBreak(); break;
 ...
 if (cond3) DoOnBreak(); break;
 ...
 }
you prove half of my point and don't address the other half
What was the other half again?
 while(cond)
 {
 ...
 if (cond2)
   DoOnBreak();
 break;
 ...   // this never runs
 if (cond3)
   DoOnBreak();
 
 break;
 ...
 }
 
 If you didn't get it correct in this case, what are the chances of making 
 an error in a more complicated case
 
Harsh. I was writing at 2am or thereabouts. Also you missed a semi-colon in your for loop above does that render anything moot? Personally I try to keep the body of a loop and in particular the control flow simple. I try to avoid breaks and put anything too large separate functions where possible.
 The other part is that it is very easy to forget to add the DoOnBreak to 
 one of the breaks (you try finding them all in old code) or adding it to 
 every new one (Now what needs to be done on break this time).
 
 Also, it will work with mixin(string) when you can't get to the string.
That might be a more valid use. Care to post an example? I think we have to be careful with mixin's. They could easily be as abused as macros. There's no reason you couldn't write with a style that has an exit condition specified in the mixin. I don't like the idea of having a mixin with a break or return hidden in it (that goes beyond the scope of the mixin itself). That could make it very hard to follow the control flow.
 scope(first):
 
 if (cond)
 {
 DoFirstTimeOnly();
 }
 while(cond)
 {
 ...
 }
 goto is evil so you want the opposite too
 
 scope(notonfirst):
 
good idea.
 while(cond)
 {
 static bool firstTime = false;
 if (firstTime==false) { firstTime = true; body1(); }
 body2();
 }
 For this case there is slight justification for something. but that
 something is a notfirst() functor.
 
 class notfirst
 {
 private:
 bool first;
 delegate doOnFirst;
 delegate doOnSubsequent;
 public:
 notfirst(delegate doOnFirst_,
 delegate doOnSubsequent_):
 first(true)
 doOnFirst(doOnFirst_),
 doOnSubsequent(doOnSubsequent_)
 {}
 void run() {
 if (first)
 {
 doOnFirst();
 first = false;
 }
 else doOnSubsequent();
 }
 };
 while(cond)
 {
 doOnFirst(body1(); body2());
 }
My eyes!!! I can't think of anything good to say about that solution.
Rather than notOnFirst I think the functor is more properly called once. once { foo(); } As a shorthand for: bool hasBeenRunOnce = false; if (hasBeenRunOnce == false) { hasBeenRunOnce = true; foo(); }
 What is this equivalent to in the worst case scenario that you need
 all four?
 
 if (!cond)
 DoIfCondNeverPasses();
 else
 {
 DoFirstTimeOnly();
 do
 {
 doOnFirst(body1();
 {
 ...
 if (cond2) DoOnBreak(); break;
 ...
 if (cond3) DoOnBreak(); break;
 ...
 }
 }
 while(cond);
 }
 DoOnCondFailed();
 
 On balance this doesn't seem like a necessary or really useful syntax
 improvement to me.
 
the same can be said for scope(failure/success/exit). It's all sugar. I think the scope(*) solution looks better and is easier to read an maintain in _all_ the cases you list.
If you have too much sugar you can get diabetes. Cut down or switch to saccharin or get yourself some insulin :)
 In all these cases the compiler can trivially implement them with copy/paste 
 and by rearranging jumps.
 
I'm more worried about the programmer having to maintain code using bizarre constructs. The compiler can be clever out of sight. Regards, Bruce.
Nov 05 2007
parent BCS <BCS pathlink.com> writes:
Bruce Adams wrote:
BCS Wrote:
Reply to Bruce,
BCS Wrote:
Right. So what you really want is something that runs when the scope ends naturally but not on a break. for(int i=5;i>0;i--) { ... break; } if (i<=0) ThisNeverRuns();
that has the same behavior but duplicates the end condition check. This can be both a performance hit and can be really bad when the condition changes or if it has side effects.
 
scope(skip):  - saves you one conditional - not very useful

if (!cond)
DoIfCondNeverPasses();
else do
{
...
}
while(cond);
mine looks better (IMHO)
It doesn't justify a syntax change (IMHO)
IIRC scope is totally redundant to begin with, your counter argument apply to it's existing functionality but people still like it.
 
scope(break): - saves you a function call or two.

while(cond)
{
...
if (cond2) DoOnBreak(); break;
...
if (cond3) DoOnBreak(); break;
...
}
you prove half of my point and don't address the other half
What was the other half again?
Below
while(cond)
{
...
if (cond2)
  DoOnBreak();
break;
...   // this never runs
if (cond3)
  DoOnBreak();

break;
...
}

If you didn't get it correct in this case, what are the chances of making 
an error in a more complicated case
Harsh. I was writing at 2am or thereabouts. Also you missed a semi-colon in
your for loop above does that render anything moot?
 Personally I try to keep the body of a loop and in particular the control flow
simple. I try to avoid breaks and put anything too large separate functions
where possible.
 
Have you ever written real code at 2AM? I'd like to have a language that helps me not make mistakes. We're all human.
 
The other part is that it is very easy to forget to add the DoOnBreak to 
one of the breaks (you try finding them all in old code) or adding it to 
every new one (Now what needs to be done on break this time).

Also, it will work with mixin(string) when you can't get to the string.
That might be a more valid use. Care to post an example? I think we have to be careful with mixin's. They could easily be as abused as macros. There's no reason you couldn't write with a style that has an exit condition specified in the mixin. I don't like the idea of having a mixin with a break or return hidden in it (that goes beyond the scope of the mixin itself). That could make it very hard to follow the control flow.
agreed, mixin can make for some nasty code.
 
In all these cases the compiler can trivially implement them with copy/paste 
and by rearranging jumps.
I'm more worried about the programmer having to maintain code using bizarre constructs. The compiler can be clever out of sight.
It's not about the compiler being clever, it about the code having fewer internal dependencies.
 Regards,
 
 Bruce.
I like the scope solution because it states stuff where it makes a difference, not where it needs to be done. Also it states stuff in a way that make the intention of the code more clear. "do this then" rather than "when that, do this" or even worse "do this now" in several places. I'll concede it is a style issue.
Nov 05 2007
prev sibling parent =?ISO-8859-1?Q?Marco_Aur=e9lio?= <thecoreh gmail.com> writes:
downs Wrote:

 if (auto foo=cast(Whee) bar) { /* use foo* }
 
 ISN'T IT NEAT?
 <3 D.
Indeed. Even better: if (auto bar = cast(Whee) bar) { } So the variable bar of type "Whee" would hide the other variable bar at the local scope. But I still think it would be usefull to have the if+with statement.
Nov 03 2007
prev sibling next sibling parent reply Charles D Hixson <charleshixsn earthlink.net> writes:
Marco Aurélio wrote:
 Hello! I've been following the development of the D programming language for
some time (around 1 year), and I have to say it keeps looking better.
 ...
 2 - for .. finally, while .. finally:
 
 This would allow having something like:
 
 while(someCondition)
 {
     DoSomething();
 } finally {
     DoOtherThing();
 }
 
 The "finally" block would be called at the end of the repetition, only if no
"break" was used. This may not seem useful at first, but I think can reduce the
number of flags needed to implement various algorithms, making the code faster
and more elegant. I'm not sure if this is already possible with scope guards.
 
 That's it.. What do you think?
No. Finally should be the label on a block of code that will be executed *WHATEVER* happens in the preceding loop, including the raising of an exception.
Nov 03 2007
parent reply =?ISO-8859-1?Q?Marco_Aur=e9lio?= <thecoreh gmail.com> writes:
Charles D Hixson Wrote:

 No.  Finally should be the label on a block of code that will 
 be executed *WHATEVER* happens in the preceding loop, 
 including the raising of an exception.
Hmm Yeah, now that I think about it, having it on that way would make it inconsistent with the try-catch-finally behavior... Maybe adding another keyword? or something like: for(int i = 0; i < 30; i++) { if (something) break; } catch (break) { Foo(); }
Nov 03 2007
parent reply Bruce Adams <tortoise_74 yeah.who.co.uk> writes:
Marco Aurélio Wrote:

 Charles D Hixson Wrote:
 
 No.  Finally should be the label on a block of code that will 
 be executed *WHATEVER* happens in the preceding loop, 
 including the raising of an exception.
Hmm Yeah, now that I think about it, having it on that way would make it inconsistent with the try-catch-finally behavior... Maybe adding another keyword? or something like: for(int i = 0; i < 30; i++) { if (something) break; } catch (break) { Foo(); }
That's redundant. Its the same as try { for(int i = 0; i < 30; i++) { if (something) throw breakException; } } catch (breakException) { Foo(); } Are you sure there's really a problem here? How about posting something 'evil'. If no-one in the group can think of a good refactoring then you may have a case. I suspect structured programming has been around too long to benefit much from anything new. That said, foreach was an awful long time coming so you may have a case. Regards, Bruce.
Nov 04 2007
parent reply BCS <ao pathlink.com> writes:
Reply to Bruce,

 Marco Aurélio Wrote:
 
 Charles D Hixson Wrote:
 
 No.  Finally should be the label on a block of code that will be
 executed *WHATEVER* happens in the preceding loop, including the
 raising of an exception.
 
Hmm Yeah, now that I think about it, having it on that way would make it inconsistent with the try-catch-finally behavior... Maybe adding another keyword? or something like: for(int i = 0; i < 30; i++) { if (something) break; } catch (break) { Foo(); }
That's redundant. Its the same as try { for(int i = 0; i < 30; i++) { if (something) throw breakException; } } catch (breakException) { Foo(); }
Tell me that is a joke. If you don't see the problems with that then.... Do you have any idea how mush potential for overhead there is in that? The other solution has one jump, that has a memory allocation (and a free at some point) a bit of stack un winding, Maybe a RTTI work and who only known what else. Plus it will (incorrectly) trigger any intervening scope(failure) and sooner or later you will need to start fabricating types to keep track of what loop the break is for.
 Are you sure there's really a problem here? How about posting
 something 'evil'. If no-one in the group can think of a good
 refactoring
 
 then you may have a case.  I suspect structured programming has been
 around too long to benefit much from anything new. That said, foreach
 was an awful long time coming so you may have a case.
 
 Regards,
 
 Bruce.
 
Nov 04 2007
parent Bruce Adams <tortoise_74 yeah.who.co.uk> writes:
BCS Wrote:

 Reply to Bruce,
 
 Marco Aurélio Wrote:
 
 Charles D Hixson Wrote:
 
 No.  Finally should be the label on a block of code that will be
 executed *WHATEVER* happens in the preceding loop, including the
 raising of an exception.
 
Hmm Yeah, now that I think about it, having it on that way would make it inconsistent with the try-catch-finally behavior... Maybe adding another keyword? or something like: for(int i = 0; i < 30; i++) { if (something) break; } catch (break) { Foo(); }
That's redundant. Its the same as try { for(int i = 0; i < 30; i++) { if (something) throw breakException; } } catch (breakException) { Foo(); }
Tell me that is a joke. If you don't see the problems with that then.... Do you have any idea how mush potential for overhead there is in that? The other solution has one jump, that has a memory allocation (and a free at some point) a bit of stack un winding, Maybe a RTTI work and who only known what else. Plus it will (incorrectly) trigger any intervening scope(failure) and sooner or later you will need to start fabricating types to keep track of what loop the break is for.
Fair point but the expense of exceptions depends on how they are implemented and what else is going on. You effectively have a form of stack unwinding when you leave a scope. An exception doesn't have to be allocated on the stack but yes its less efficient than a break. I try to avoid using breaks myself because they pollute the control flow too much. Likewise exceptions but they are not supposed to be used for control flow. I should know better. How about: bool breakNow = false; for(int i = 0; i < 30 && breakNow == false; i++) { if (something) breakNow = true; ... } if (breakNow) { Foo(); } It still doesn't justify a language enhancement as far as I can see.
 Are you sure there's really a problem here? How about posting
 something 'evil'. If no-one in the group can think of a good
 refactoring
 
 then you may have a case.  I suspect structured programming has been
 around too long to benefit much from anything new. That said, foreach
 was an awful long time coming so you may have a case.
 
 Regards,
 
 Bruce.
 
Nov 05 2007
prev sibling next sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Marco Aurélio Wrote:

 2 - for .. finally, while .. finally:
 
 This would allow having something like:
 
 while(someCondition)
 {
     DoSomething();
 } finally {
     DoOtherThing();
 }
 
 The "finally" block would be called at the end of the repetition, only if no
"break" was used. This may not seem useful at first, but I think can reduce the
number of flags needed to implement various algorithms, making the code faster
and more elegant. I'm not sure if this is already possible with scope guards.
 
 That's it.. What do you think?
Another "eh"... I just can't see its limited use justifying the added complexity.
Nov 03 2007
prev sibling parent reply Bruce Adams <tortoise_74 yeah.who.co.uk> writes:
BCS Wrote:

 Bruce Adams wrote:
BCS Wrote:
Reply to Bruce,
BCS Wrote:
Right. So what you really want is something that runs when the scope ends naturally but not on a break. for(int i=5;i>0;i--) { ... break; } if (i<=0) ThisNeverRuns();
that has the same behavior but duplicates the end condition check. This can be both a performance hit and can be really bad when the condition changes or if it has side effects.
The performance and side effects problems can't be avoided with your sugar either. Is this not what your syntactic sugar is supposed to alias to? If not, then what? Repeating code that changes is as always an issue but if its a complex condition it could (arguably should) be a function instead.
 
scope(skip):  - saves you one conditional - not very useful

if (!cond)
DoIfCondNeverPasses();
else do
{
...
}
while(cond);
mine looks better (IMHO)
It doesn't justify a syntax change (IMHO)
IIRC scope is totally redundant to begin with, your counter argument apply to it's existing functionality but people still like it.
I see I needed to RTFM. I see you are suggesting an extension to existing syntax I missed. Still it makes me uneasy. Overuse of this feature will make for very hard to read code. scope(exit) serves a very particular purpose to replace RAII where destructors can't be used because of GC. I don't actually get scope(success) and scope(failure) yet (have to RTFM some more). success and failure of what exactly? The page eplicitly says scope doesn't catch exceptions. Its only for replacing the finaly of a try catch finally.
 
scope(break): - saves you a function call or two.

while(cond)
{
...
if (cond2) DoOnBreak(); break;
...
if (cond3) DoOnBreak(); break;
...
}
you prove half of my point and don't address the other half
What was the other half again?
Below
while(cond)
{
...
if (cond2)
  DoOnBreak();
break;
...   // this never runs
if (cond3)
  DoOnBreak();

break;
...
}

If you didn't get it correct in this case, what are the chances of making 
an error in a more complicated case
Harsh. I was writing at 2am or thereabouts. Also you missed a semi-colon in
your for loop above does that render anything moot?
 Personally I try to keep the body of a loop and in particular the control flow
simple. I try to avoid breaks and put anything too large separate functions
where possible.
 
Have you ever written real code at 2AM?
Frequently.
 I'd like to have a language that 
   helps me not make mistakes. We're all human.
I use unit tests, design by contract, lint and -Wall but every little helps. But you prove my point. At 2am reading code with multiple complex paths of control flow is painful.
 
The other part is that it is very easy to forget to add the DoOnBreak to 
one of the breaks (you try finding them all in old code) or adding it to 
every new one (Now what needs to be done on break this time).

Also, it will work with mixin(string) when you can't get to the string.
That might be a more valid use. Care to post an example? I think we have to be careful with mixin's. They could easily be as abused as macros. There's no reason you couldn't write with a style that has an exit condition specified in the mixin. I don't like the idea of having a mixin with a break or return hidden in it (that goes beyond the scope of the mixin itself). That could make it very hard to follow the control flow.
agreed, mixin can make for some nasty code.
I'd still like to see a real worldish example where new syntax helps significantly.
 
 I'm more worried about the programmer having to maintain code using bizarre
constructs. The compiler can be clever out of sight.
 
It's not about the compiler being clever, it about the code having fewer internal dependencies. I like the scope solution because it states stuff where it makes a difference, not where it needs to be done. Also it states stuff in a way that make the intention of the code more clear. "do this then" rather than "when that, do this" or even worse "do this now" in several places. I'll concede it is a style issue.
I like the idea of "do this then" versus "do this now". Its breaks out of in the procedural (and even message passing OO style) where pretty much everything is now but I'm not entirely convinced this is the best way to express it. The body of a loop should have stuff to do with its body only. A finally block is in the right place, at the end for example (that's not to imply I like the earlier suggestion of adding finally blocks to loops either). Regards, Bruce.
Nov 05 2007
next sibling parent Bruce Adams <tortoise_74 yeah.who.co.uk> writes:

 I see I needed to RTFM. I see you are suggesting an extension to >existing
syntax I missed. Still it makes me uneasy. Overuse of this >feature will make
for very hard to read code. scope(exit) serves a >very particular purpose to
replace RAII where destructors can't be >used because of GC. I don't actually
get scope(success) and >scope(failure) yet (have to RTFM some more). success
and failure of >what exactly? The page eplicitly says scope doesn't catch
>exceptions. Its only for replacing the finaly of a try catch finally.
Right I have found after some digging Andrei Alexandrescu's original suggestion. "I believe three constructs would simplify writing robust code: 1. on_scope_exit { ... code .. } Executes code upon the current scope's exit. Several on_scope_exit blocks in a scope are executed LIFO. 2. on_scope_success { ... code ... } Executes code if the current scope is exited normally (no exception engendered). 3. on_scope_failure { ... code ... } Executes code if the current scope is exited via an exception. " All specifically to do with exception safety. Its mentioned in passing on at least two pages (links below) but lacking (as far as I can see lacking a clear definition like this on the digital mars web-site. http://www.digitalmars.com/d/statement.html http://www.digitalmars.com/d/exception-safe.html
Nov 05 2007
prev sibling parent BCS <ao pathlink.com> writes:
Reply to Bruce,

 BCS Wrote:
 
 Bruce Adams wrote:
 
 for(int i=5;i>0;i--)
 {
 ...
 break;
 }
 if (i<=0) ThisNeverRuns();
that has the same behavior but duplicates the end condition check. This can be both a performance hit and can be really bad when the condition changes or if it has side effects.
The performance and side effects problems can't be avoided with your sugar either. Is this not what your syntactic sugar is supposed to alias to? If not, then what? Repeating code that changes is as always an issue but if its a complex condition it could (arguably should) be a function instead.
no, the thought is that you can play games with what break does to get the effect. for(int i=5;i>0;i--) { ... goto breakpoint; //break; } ThisNeverRuns(); breakpoint:; as for performance, there is none as the break is a "jump to the end" and the result is a "jump to (a bit after) the end". mixing several scope(last) and scope(break) could get fun though.
 I like the idea of "do this then" versus "do this now". Its breaks out
 of in the procedural (and even message passing OO style) where pretty
 much everything is now but I'm not entirely convinced this is the best
 way to express it. The body of a loop should have stuff to do with its
 body only. A finally block is in the right place, at the end for
 example (that's not to imply I like the earlier suggestion of adding
 finally blocks to loops either).
after thinking of all the cases I'd want, I think that there is a place here for something but if the structure isn't carefully considered, then it might do more harm than good.
 
 Regards,
 
 Bruce.
 
Nov 05 2007