digitalmars.D - Ideas regarding flow control and loops
- =?ISO-8859-1?Q?Marco_Aur=e9lio?= (37/37) Nov 03 2007 Hello! I've been following the development of the D programming language...
- downs (9/27) Nov 03 2007 I used to have the same problem - I even wrote an ifIs template to get
- Daniel Keep (11/41) Nov 03 2007 else would also be nice.
- =?ISO-8859-1?Q?Marco_Aur=e9lio?= (11/12) Nov 03 2007 This would be specially usefull for implementing collisions on 2D games ...
- downs (24/39) Nov 03 2007 Well, technically ...
- Robert Fraser (2/25) Nov 03 2007 Heh, closures are already spreading their intoxicating power.
- =?ISO-8859-1?Q?Marco_Aur=e9lio?= (2/29) Nov 03 2007 Wow. I didn't know you could do that, even with closures.
- downs (5/32) Nov 03 2007 It doesn't actually use closures. Completely D 1.0 :)
- Bruce Adams (10/25) Nov 04 2007 What's wrong with:
- BCS (10/44) Nov 03 2007 I'd rather an extension of the scope syntax
- Bruce Adams (94/142) Nov 04 2007 Lets take these one at a time:-
- BCS (33/151) Nov 04 2007 for(int i = 5; i>0 i--)
- Bruce Adams (34/194) Nov 05 2007 Right. So what you really want is something that runs when the scope end...
- BCS (18/110) Nov 05 2007 that has the same behavior but duplicates the end condition check. This
- =?ISO-8859-1?Q?Marco_Aur=e9lio?= (5/9) Nov 03 2007 Indeed. Even better:
- Charles D Hixson (4/20) Nov 03 2007 No. Finally should be the label on a block of code that will
- =?ISO-8859-1?Q?Marco_Aur=e9lio?= (9/12) Nov 03 2007 Hmm Yeah, now that I think about it, having it on that way would make it...
- Bruce Adams (15/30) Nov 04 2007 That's redundant. Its the same as
- BCS (8/50) Nov 04 2007 Tell me that is a joke. If you don't see the problems with that then....
- Bruce Adams (17/72) Nov 05 2007 Fair point but the expense of exceptions depends on how they are impleme...
- Robert Fraser (2/16) Nov 03 2007 Another "eh"... I just can't see its limited use justifying the added co...
- Bruce Adams (13/126) Nov 05 2007 The performance and side effects problems can't be avoided with your sug...
- Bruce Adams (16/18) Nov 05 2007 Right I have found after some digging Andrei Alexandrescu's
- BCS (16/49) Nov 05 2007 no, the thought is that you can play games with what break does to get t...
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
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
downs wrote:Marco Aurélio wrote:Oh hell yeah.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.else would also be nice. foreach( foo ; bar ) DoSomethingWith(foo); finally DoSomethingAfterwards(); else DoSomethingElseSinceBarIsEmpty(); But maybe that's just me. -- Daniel2 - 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
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
Marco Aurélio wrote:Daniel Keep Wrote: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"); } ); }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
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
Robert Fraser Wrote:downs Wrote:Wow. I didn't know you could do that, even with closures.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
Robert Fraser wrote:downs Wrote:It doesn't actually use closures. Completely D 1.0 :) Those { } things are short-hand for () { }, i.e. completely normal delegate literals. --downsPS: 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
Marco Aurélio Wrote:Daniel Keep Wrote: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.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 04 2007
Reply to Daniel,downs 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; ... }Marco Aurélio wrote:else would also be nice. foreach( foo ; bar ) DoSomethingWith(foo); finally DoSomethingAfterwards(); else DoSomethingElseSinceBarIsEmpty(); But maybe that's just me. -- Daniel2 - 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
BCS Wrote:Reply to Daniel,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.downs 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; ... }Marco Aurélio wrote:else would also be nice. foreach( foo ; bar ) DoSomethingWith(foo); finally DoSomethingAfterwards(); else DoSomethingElseSinceBarIsEmpty(); But maybe that's just me. -- Daniel2 - 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 04 2007
Reply to Bruce,BCS Wrote:for(int i = 5; i>0 i--) { scope(last) ThisNeverRuns(); break; }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);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
BCS Wrote:Reply to Bruce,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();BCS Wrote:for(int i = 5; i>0 i--) { scope(last) ThisNeverRuns(); break; }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();It doesn't justify a syntax change (IMHO)scope(skip): - saves you one conditional - not very useful if (!cond) DoIfCondNeverPasses(); else do { ... } while(cond);mine looks better (IMHO)What was the other half again?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 halfwhile(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 caseHarsh. 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.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(); }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.If you have too much sugar you can get diabetes. Cut down or switch to saccharin or get yourself some insulin :)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.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
Bruce Adams wrote:BCS Wrote: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.Reply to Bruce,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();BCS Wrote:IIRC scope is totally redundant to begin with, your counter argument apply to it's existing functionality but people still like it.It doesn't justify a syntax change (IMHO)scope(skip): - saves you one conditional - not very useful if (!cond) DoIfCondNeverPasses(); else do { ... } while(cond);mine looks better (IMHO)BelowWhat was the other half again?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 halfyour for loop above does that render anything moot?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 caseHarsh. I was writing at 2am or thereabouts. Also you missed a semi-colon inPersonally 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.agreed, mixin can make for some nasty code.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.It's not about the compiler being clever, it about the code having fewer internal dependencies.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.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
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
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
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
Marco Aurélio Wrote:Charles D Hixson Wrote: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.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 04 2007
Reply to Bruce,Marco Aurélio Wrote: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.Charles D Hixson Wrote:That's redundant. Its the same as try { for(int i = 0; i < 30; i++) { if (something) throw breakException; } } catch (breakException) { Foo(); }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(); }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
BCS Wrote:Reply to Bruce,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.Marco Aurélio Wrote: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.Charles D Hixson Wrote:That's redundant. Its the same as try { for(int i = 0; i < 30; i++) { if (something) throw breakException; } } catch (breakException) { Foo(); }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(); }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
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
BCS Wrote:Bruce Adams wrote: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.BCS Wrote: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.Reply to Bruce,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();BCS Wrote: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.IIRC scope is totally redundant to begin with, your counter argument apply to it's existing functionality but people still like it.It doesn't justify a syntax change (IMHO)scope(skip): - saves you one conditional - not very useful if (!cond) DoIfCondNeverPasses(); else do { ... } while(cond);mine looks better (IMHO)Frequently.BelowWhat was the other half again?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 halfyour for loop above does that render anything moot?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 caseHarsh. I was writing at 2am or thereabouts. Also you missed a semi-colon inPersonally 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.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.I'd still like to see a real worldish example where new syntax helps significantly.agreed, mixin can make for some nasty code.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.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.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.
Nov 05 2007
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.htmlI 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.
Nov 05 2007
Reply to Bruce,BCS Wrote: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.Bruce Adams wrote: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.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.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