Ideas regarding flow control and loops

Bruce Adams tortoise_74 at yeah.who.co.uk
Mon Nov 5 04:27:33 PST 2007


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.



More information about the Digitalmars-d mailing list