4

How can I do this cleanly without gotos?

loop:
  if(condition1){
    something();
  } else if (condition2) {
    somethingDifferent();
  } else {
    mostOfTheWork();
    goto loop;
  }

I'd prefer not to use breaks as well. Furthermore, it is expected to loop several (adv 40) times before doing something else, so the mostOfTheWork part would most likely be as high up as possible, even if just for readability. Thanks in advance.

EDIT: This was posted under the misconception that the compiler optimizer worked poorly with breaks, which, while generally stupid to begin with, I have proven incorrect to myself through experimentation (of performance). On the other hand, thank you for your answers; they have been interesting reads on varying styles.

Jared Pochtar
  • 4,925
  • 2
  • 29
  • 39
  • 1
    any particular language; Ruby, PHP, C#, Java, etc? – Kane Apr 02 '10 at 21:33
  • 5
    Why not use breaks? That's what they're there for, and required for this case, unless I'm just not that clever, which is probably the case. As a side note: may want to put what language this is, might matter. – Nick Craver Apr 02 '10 at 21:34
  • 1
    Please state your requirements for not using breaks. It is, generally, apart of the language and legal to use, so why not use them? – Natalie Adams Apr 02 '10 at 21:35
  • Yeah, seriously, why no `break`? Is this for school or something? – SamB Apr 02 '10 at 22:15
  • Out of curiosity, what made you think that compiler optimization would work poorly with breaks? – Stephen Canon Apr 02 '10 at 23:33
  • One of the key tenets of Structured Programming is that a control structure should have exactly one entry and exactly one exit. This allows you to know exactly where and how the control structure exits, and what will be true at that time. (Read Dijkstra's "GOTO Statement Considered Harmful", then read Dijkstra's segment of "Structured Programming", by Dahl, Dijkstra & Hoare.) Using multiple "break" statements, by definition, breaks that rule. – John R. Strohm Apr 03 '10 at 14:35
  • it's **ridiculous** you 'don't want to use breaks'. totally bizarre. – Fattie Jul 07 '14 at 11:01

8 Answers8

10
bool done = false ;

while( !done ) {
  if(condition1){
    something();
    done = true ;
  } else if (condition2) {
    somethingDifferent();
    done = true ;
  } else {
    mostOfTheWork();
  }
} 
tpdi
  • 34,554
  • 11
  • 80
  • 120
10

Clearly, you will break out of the loop if either condition fires.

    while ((!condition1) && (!condition2)) {
      MostOfTheWork();
    }
    if (condition1) {
      something();
    } else if (condition2) {
      somethingDifferent();
    }

So, loop while neither condition has fired, then see which one got you.

Now, someone will scream that I evaluated the conditions more than I needed to. For their benefit, a modified version:

{
  bool t1, t2;
  while ((!(t1 = condition1)) && (!(t2 =condition2))) {
    MostOfTheWork();
  }
  if (t1) {
    something();
  } else if (t2) {
    somethingDifferent();
  }
}
John R. Strohm
  • 7,547
  • 2
  • 28
  • 33
  • 1
    +1 I think this is the solution displaying the sharpest observation. – Decent Dabbler Apr 02 '10 at 21:42
  • 1
    @Yacoby: Nope! Recall that the C and C++ standards are very explicit in requiring that && do short-circuit evaluation. If the first branch of an &&-expression fires, the second branch is not evaluated. – John R. Strohm Apr 02 '10 at 21:55
2

Without breaks?

function foo(){
  if(condition1){
    something();
    return;
  } else if (condition2) {
    somethingDifferent();
    return;
  }
  mostOfTheWork();
  foo(); //(Tail recursive for those worried about stack overflows)
}

However, breaks are there for flow control, they are much clearer as to what they do than goto, so I would recommend using them. However in this case I would recommend @John's answer as the correct way to do it.

Community
  • 1
  • 1
Yacoby
  • 54,544
  • 15
  • 116
  • 120
  • 1
    Not all languages will optimize tail calls. This could still cause stack overflow in many languages. – R Samuel Klatchko Apr 02 '10 at 22:24
  • In this, the tenth year of the 21st century, a "production quality" compiler that does not optimize tail calls is hopelessly brain-dead. The idea has been around for more than three decades: read the "Lambda: the Ultimate ..." series of MIT AI Lab memos. – John R. Strohm Apr 03 '10 at 14:38
1

No gotos or beaks. Cleaniless as always, subjective

 do {
   if ( condition1 )
     something();
   else if( condition2 )
     somethingElse();
   else
     mostOfTheWork();
 } while( !(condition1 || condition2) );

This is of course, incredibly silly. Just use a break.

Logan Capaldo
  • 39,555
  • 5
  • 63
  • 78
1

You've probably had it drilled into your head by CS professors that it's bad and will wreak havoc in your code. Gotos are actually quite efficient when used properly and purposely. This is why most programming languages haven't dropped it.

In your particular case, the goto is fine because the block of code is small and you can easily see the program flow. You can write spaghetti code with other control structures too, although it's a little harder to do.

ATL_DEV
  • 9,256
  • 11
  • 60
  • 102
0

In my opinion this version of the code most clearly communicates the program flow to posterity, and is the most easily extended. Yes, I'm using break. I can't think of any real reason not to.

while(true)
{
    if (condition1)
    {
        something();
        break;
    }
    if (condition2)
    {
        somethingDifferent();
        break;
    }
    mostOfTheWork();
}

If you really don't want to use break, you can use goto to get out of the loop, or use return to bail out of the function (if this loop is part of a larger function you'd have to refactor).

while(true)
{
    if (condition1)
    {
        something();
        goto exit;
    }
    if (condition2)
    {
        somethingDifferent();
        goto exit;
    }
    mostOfTheWork();
}
exit:

Or

while(true)
{
    if (condition1)
    {
        something();
        return;
    }
    if (condition2)
    {
        somethingDifferent();
        return;
    }
    mostOfTheWork();
}

And if you refuse to use any flow control other than if and while, how about this one:

bool ok = true;
while(ok)
{
    if (condition1)
    {
        something();
        ok = false;
    }
    if (ok && condition2)
    {
        somethingDifferent();
        ok = false;
    }
    if (ok)
    {
        mostOfTheWork();
    }
}

Also, please see my canonical answer for this sort of question (and vote for it!)

Community
  • 1
  • 1
John Wu
  • 50,556
  • 8
  • 44
  • 80
0

Since you weren't specific about a language, some languages have continue, next or skip that you can use in place of that goto.

Forgotten Semicolon
  • 13,909
  • 2
  • 51
  • 61
0
do
{
  if(condition1){
    something();
  } else if (condition2) {
    somethingDifferent();
  } else {
    mostOfTheWork();
  }
} while (!condition1 && !condition2)
Byron Whitlock
  • 52,691
  • 28
  • 123
  • 168