Loops are gotos


Here’s an interesting question I got the other day:

We are writing code to translate old mainframe business report generation code written in a BASIC-like language to C#. The original language allows “goto” branching from outside of a loop to the interior of a loop, but C# only allows branching the other way, from the interior to the exterior. How can we branch to the inside of a loop in C#?

I can think of a number of ways to do that.

First, don’t do it. Write your translator so that it detects such situations and brings them to the attention of a human who can analyze the meaning of the code and figure out what was meant by the author of this bad programming practice. Branching into the interior of a loop is illegal in C# because doing so would skip all of the code that is necessary to ensure the correct behaviour of the loop. Odds are good that this pattern indicates a bug or at least some bad smelling code that should be looked at by an expert.

Second, this pattern is not legal in C# or VB.NET, but perhaps it is legal in another useful modern language. You could write your translator to translate to some other language instead of C#.

Third, if you want to do this automatically and you need to use C#, the trick is to change how you generate your loops. Remember, loops are nothing more than a more pleasant way to write a “goto”. Suppose your original code looks something like this pseudo-basic fragment:

10   J = 2
20   IF FOO THEN GOTO 50
30   FOR J = 1 TO 10
40     PRINT J
50     PRINT “—“
60   NEXT
70   PRINT “DONE”

The “obvious” way to translate this program fragment into C# doesn’t work:

     int J = 2;
     if (FOO) goto L50;
     for(J = 1 ; J <= 10; J = J + 1)
     {
       PRINT (J);
L50:   PRINT (“—“);
     }
     PRINT (“Done”);

because there’s a branch into a block. But you can eliminate the block by recognizing that a “for” loop is just a sugar for “goto”. If you translate the loop as:

     int J = 2;
     if (FOO) goto L50;
     J = 1;
L30: if (!(J <= 10)) goto L70;
       PRINT (j);
L50:   PRINT (“—“);
     J = J + 1;
     goto L30;
L70: PRINT (“done”);

and now, no problem. There’s no block to branch into, so there’s no problem with the goto. This code is hard to read so you probably want to detect the situation of branching into a loop and only do the “unsugared” loop when you need to.

It is difficult to do a similar process that allows arbitrary branching in a world with try-finally and other advanced control flow structures, but hopefully you do not need to. Old mainframe languages seldom have complex control flow structures like “try-finally”.

Comments (58)

  1. Pavel Minaev says:

    > Branching into the interior of a loop is illegal in C# because doing so would skip all of the code that is necessary to ensure the correct behaviour of the loop.

    Can you elaborate? Do you mean the loop condition for while-loops, and also the initializer for for-loops (in which case goto silently breaks the semantics of the loop – but this seemingly doesn’t apply to do-while), or some other code that the compiler generates undercover?

    It’s more general than loops. In C# it is illegal to branch into the middle of any block from outside the block. With loops, one wants to be able to reason about the invariants of a loop without having to understand how control could have entered the loop. More generally, one should be able to reason about the control flow within a given block solely by looking at that block. You should not have to look at the whole method to understand how a given block in it could be used.

    Another way to look at this is to think of the name of the label as being scoped to the block, just like the name of a local declared in the block is scoped to the block. Just as you cannot refer to a local by name outside of its scope, you cannot refer to a label by name outside of its scope. 

     — Eric

  2. Clinton Pierce says:

    In a previous life, I had to do just such a beast and wound up doing exactly what you suggested.  However I could do some static analysis and only write the IF/GOTO loop if there were a /targeted/ label inside of the original FOR loop.  Otherwise, I’d write the more natural corresponding FOR loop.

    If I did have to write the IF/GOTO loop I would insert a comment block that indicated what it read originally (FOR) and where the reference to the inner label came from.  This facilitated hand-massaging the code later into something more manageable.

    Thank goodness there were no COME FROM constructs!  🙂

  3. A. C. Hynes says:

    You can’t do Duff’s Device in C#?! Jeez.

    Gotos are fun. I wrote a (lexer) state machine once with no loop. It just bounced around with gotos until it bounced into an endpoint.

    It’s weird, but good, that we’ve reached a point when gotos are an exotic construct that you never think about.

  4. Pop Catalin says:

    Simple suggestion, unroll the part of the loop that is being jumped to, outside of the loop, and insert that part at the jump location … This could get a little complicated if the jump traverses many branches of code, but otherwise I think it could be an option …

  5. configurator says:

    When you say this is legal in VB, you mean VB6, right – not VB.Net?

    Bizarre. The customer who asked me about this issue said that it worked in VB.Net, but I have just checked the documentation and clearly it does not. Thanks for noticing that. — Eric

     

  6. Ross says:

    So how would you translate this into oh, FORTH, or Python, for example, neither of which has labels.. You need to figure out what the program REALLY needs to do and do it without spaghetti (even flying spaghetti monster) code.

  7. Graham Stewart says:

    Personally if I was going to manually refactor that code then I’d ditch the GOTOs altogether and just do something like:

    IF (FOO) THEN

     PRINT "—"

     FOR J = 3 TO 10

       PRINT J

       PRINT "—"

     NEXT

    ELSE

     FOR J = 1 TO 10

       PRINT J

       PRINT "—"

     NEXT

    ENDIF

    PRINT "DONE"

    Sure it’s a lot more verbose, but I find it a lot easier to read than the translated block with the looping GOTOs in it.

  8. Lee says:

    When people realize today’s if-else are also gotos, there’s gonna be rioting in the streets! 😉

  9. Malcolm Fitzsimmons says:

    Cleaner would be:

    INTEGER JBASE

    IF (FOO) THEN

        PRINT "—"

        JBASE = 3

    ELSE

        JBASE = 1

    END IF

    FOR J = JBASE TO 10

        PRINT J

        PRINT "—"

    NEXT

    PRINT "DONE"

  10. Tanveer Badar says:

    Suppose you have something like this:

    int i = 0;

    if( j < 5 ) goto inside;

    for( ; i < 10 ; ++i )

    {

      do_something( );

    inside:

     do_more( );

    }

    Then why can’t you translate it like this?

    int i = 0;

    if( j < 5 ) do_something( );

    for( ++i ; i < 10 ; ++i )

    {

      do_something( );

    inside:

     do_more( );

    }

    This is exactly what Pop Catalin suggested. It will vary on case by case basis, but it is easier to do and more easier to understand.

  11. Graham Stewart says:

    @Malcolm Fitzsimmons:

    Agreed. I would probably pick between that style or my style depending on a few factors, such as how big the actual loop body was, how big the body of the FOO clause was and how often I expected FOO to be true.

  12. Bruno Martínez says:

    Read "Structured Programming with go to Statements".  That goto breaks invariant reasoning techniques was established to be wrong.

  13. <Quote> Remember, loops are nothing more than a more pleasant way to write a "goto". </Quote>

    Your momma’s a "goto."

  14. Bob says:

    On Error Goto Hell

    Hell:

       MsgBox "Before advanced control flow structures like try-finally, there were gotos."

  15. Pavel Minaev says:

    My favorite "goto loop" pattern:

     do { // you think that’s a loop? ha!

       …

       if (something) break; // look, no goto!

       …

     } while (false); // look, no label either!

    Yeah, I worked with a guy who really liked that one.

  16. Patrick says:

    Back in highschool, in my first programing class (Qbasic) our instructor forbade us from using goto’s… if your assignment had one goto in it…. he would trash it… THANK GOD! 8 years later MCAD certified, working for an awesome company… and i would have never gotten this far if I would have been allowed to think that goto was a good thing…

  17. Lee says:

    Eliminating goto was supposed to be the panacea for spaghetti code, and yet it continues to plague what could otherwise be fabulous code… Curious…

  18. pminaev says:

    Guys, goto is not by itself a bad thing in any way. Its evilness is that it is very easy to misuse it, but by itself it is a useful tool in any imperative programming languages. Did you never have to break out of a nested loop? Or a switch nested inside a loop? And if you’re coding in C (not C++), goto is essentially the only robust way to do proper error handling, when you have to check for error (and potentially clean up) after every single function call.

    The extreme argument against goto ("Goto is always evil. Always!") is also the argument against break and return, and, to some extent, throw. If you are truly willing to go to these lengths, then you should go all the way, and claim that nothing less than the purity of Haskell is desirable. Which would at least be a consistent position, even though not a very pragmatic one.

    But, so long as you stick to an imperative language, some form of goto is necessary and desirable.

  19. By the way you can do a Duff’s device in c#

    static void DuffsDevice<T>(T[] from, T[] to)

    {

    int count = from.Length;

    int position = 0;

    switch (count % 8)

    {

    case 0:

    to[position] = from[position++];

    goto case 7;

    case 7:

    to[position] = from[position++];

    goto case 6;

    case 6:

    to[position] = from[position++];

    goto case 5;

    case 5:

    to[position] = from[position++];

    goto case 4;

    case 4:

    to[position] = from[position++];

    goto case 3;

    case 3:

    to[position] = from[position++];

    goto case 2;

    case 2:

    to[position] = from[position++];

    goto case 1;

    case 1:

    to[position] = from[position++];

    if ((count -= 8) > 0) goto case 0; else break;

    }

  20. Graham Stewart says:

    @pminaev:

    An example of combined error-handling in C without using goto:

    bool got_error = FALSE;

    got_error = do_func_1();

    got_error = got_error && do_func_2();

    got_error = got_error && do_func_3();

    got_error = got_error && do_func_4();

    if (got_error) {

     // combined error handling

    }

  21. Graham Stewart says:

    Oops, wrong logic (it’s early) but you get the idea.

  22. pminaev says:

    That’s assuming your functions return bool to indicate error – what about an int error code (note that in that case, && cannot be used, as it will coerce any non-0 "truth" value to 1)?

    In practice, most C code I’ve seen uses "if … goto error" and so on. Probably also because it’s far clearer than this trick, too. As I’ve said earlier, sometimes goto is the right way to solve the problem, and working around it only makes things more complicated, all for the sake of "not saying the dreaded word".

  23. ted says:

    We constantly use gotos in all forms except for jumping into a loop or back to the top of a function.

    This is our way of drastically reducing the nesting level of if then else/for loops/etc.  This point is lost when must younger developers trust the framework to clean up their own objects/allocation and ignore the longer term support cost for a particular block of code.  

    We’ve been burned with offshore written code that has 15+ levels of nesting in 500+ line functions because the developers refused to use gotos, returns and apparently got paid more for each line of code.

    Common code we’ve seen

    if (file open is ok)

    {

     500+ lines of code

    }

    else

    {

    do some error handling

    }

    This would be nested inside of a loop or multiple levels down inside of an if/then else block.

    Another example would be multiple nested try/catch statements each to handle a resource allocation/connection failure instead the commonly used block:

    if allocate 1 fails goto cleanup_one

    if allocate 2 fails goto cleanup_two

    if allocate 3 fails goto cleanup_three

    body of function (or better a function call to the body to make it easier to see that the allocate and cleanup operations are done in the correct order)

    cleanup_three: do cleanup of object 3

    cleanup_two: do cleanup of object 2

    cleanup_one: do cleanup of object 1

    return

  24. Graham Stewart says:

    @pminaev: int error code can easily be handled in the same way by ANDing got_error with the result of comparing the function to the known good value e.g. if a negativereturn vale indicates error then:

    got_error = !got_error && (func1() < 0);

    If you dislike the "trick" with the logic short-circuiting then you can use a more explicit version:

    bool got_error = FALSE;

    got_error = do_func_1();

    if (!got_error)

       got_error = do_func_2();

    if (!got_error)

       got_error = (do_func_3() < 0);

    if (got_error) {

       // combined error handling

    }

    Either way, the only advantage to the goto approach is that it saves a couple of clock cycles. On most platforms, including most embedded system I’ve worked on, a few clock cycles in neglible.

  25. pminaev says:

    > Either way, the only advantage to the goto approach is that it saves a couple of clock cycles.

    You still miss my point. The advantage of the goto error handling approach is that it is usually more readable than any other workaround. Workarounds for the sake of them are not a good idea.

  26. I always used to think that the GOTO statement was a bad thing, and programming should only use loops and other "prettier" flow techniques.

    Over the last few weeks I was playing around writing an MSIL disassembler to look deeper into the code I write… and the first thing I noticed was that compiler translate loops into a seried of GOTO blocks. Typically a for loop would look something equivalent to:

                 (Initialise looping variable)

                 goto LABEL1;

    LABEL2: (Whatever instructions are inside the block)

                 (Increment or decrement looping variable as required)

    LABEL1: if (Check for loop to be run) goto LABEL 2;

    So a trivial loop:

    for (int ix = 0; ix < 10; ix++)

    {

     do_something();

    }

    do_loop_finished();

    gets translated to:

                 int ix = 0;

                 goto LABEL1;

    LABEL2: do_something();

                 ix++;

    LABEL1: if (ix < 10) goto LABEL 2;

                 do_loop_finished();

    So I am now wondering why we are always told to you loops rather than gotos, when they are just converted back to gotos, thus adding an additional level of translation (and hence sub-optimal code)!

  27. evilhamburger says:

    I agree that gotos can be VERY evil…

    BUT, they are very useful. I had to write a parser for fiels that could reach up to 20 gigs. Their content was never known until they were read. I came up with a 400 line optimised function, each of the other programmers came up with 700+ line functions.

    They had similar flow patterns, except I used goto statements.

    <quote>

    Common code we’ve seen

    if (file open is ok)

    {

    500+ lines of code

    }

    else

    {

    do some error handling

    }

    </quote>

    solution…

    if (!FileOpenIsOk)

    {

    error handling

    }

    function continues

  28. Graham Stewart says:

    @pminaev:

    I agree that avoiding "goto" purely out of superstition is a bad idea. But I disagree that a goto version of that code is actually any more readable.

    @Russell Anscomb:

    Of course. And this is true of most languages. Loops are all just syntactic sugar for various Branch and Jump assembly instructions. Languages themselves are just abstractions of machine code. If you want absolute speed at all cost then why are you using a high-level language at all? You need to write directly in assembler (and you also need to be a genius to outperform most modern compilers).

    However the rest of us see the benefit of readable and maintainable high-level code over absolute performance.

  29. Graham Stewart says:

    It’s probably also worth pointing out that in a modern language, like C#, most error handling will be done by exceptions – which in many ways offer all the same benefits as gotos in this scenario, with the added advantage of carrying information about why they were raised.

  30. Of course ALL flow control becomes "goto" (possibly conditional) at the machine level. Anyone who does not understand that, needs to just hang up their had.

    Much more dangerous than "goto" is the infamous "come from" instruction. When

    using this, you can cause an arbitrary transfer from any point in the code:

    10 x = 1

    20 y = 1

    30 x = 2

    40 Print x,y,z

    5000 Come From 20

    5001 y = 99

    5002 GoBack

    (Sorry for posting this 14 days before it’s 35th original publication)

  31. Florian Standhartinger says:

    So you cant jump to a goto label within a loop from outside the loop? I didnt know this. But whats that piece of code that Reflector happens to show when decompiling a yield return statemachine?

       private bool MoveNext()

           {

               try

               {

                   switch (this.<>1__state)

                   {

                       case 0:

                           this.<>1__state = -1;

                           this.<>7__wrap4 = this.<>4__this.GetNodes().GetEnumerator();

                           this.<>1__state = 1;

                           while (this.<>7__wrap4.MoveNext())

                           {

                               this.<node>5__3 = this.<>7__wrap4.Current;

                               this.<>4__this.m_alreadyReturnedNodes.Add(this.<node>5__3);

                               this.<>2__current = this.<node>5__3;

                               this.<>1__state = 2;

                               return true;

                           Label_008C:

                               this.<>1__state = 1;

                           }

                           this.<>m__Finally5();

                           break;

                       case 2:

                           goto Label_008C;

                   }

                   return false;

               }

               fault

               {

                   this.System.IDisposable.Dispose();

               }

           }

    Is it just Reflector making up a while statement while the original il statements just are gotos?

    Regards Florian

  32. Klaas Oosterhuis says:

    The discussion is moving a litle away from the first remark about automated migrated code.

    Yes excessive and wrong use of Goto is very bad. But looking manual at 10.000.000 lines to remove them is a huge task. Analyzing and refactoring code solves a number of them but still not all.

    The IL itself does allow it so why not the compiler. Let the programmer be the judge to use it or not.

    In vb.net indead the goto into a for is not allowed but a goto into an if is. And possible other code levels?

           Dim j As Integer

           j = 1

           GoTo l50    ‘ <—- allowed

           If (1 = 1) Then

               j = 2

    l50:

               j = 3

           End If

           GoTo l60  ‘<———– not allowed

           For j = 1 To 5

    l60:

           Next

  33. Gert-Jan van der Kamp says:

    I’m suprised that people can be so ‘religious’ in their renouncing of gotos. I thought kind of singlemindedness was a Java guy’s thing.

    Yes, most of the time the higher level control flows are better, but there are exeptions.

    Take the example of a controlflow schema from Visio. When you want to implement that with functions, you have a problem because after the call ends, you end up where you called the function. That’s not what you want, you wanted to go to another Process or Decision. (note the use of the words ‘go’ and  ‘to’ 😉 In those cases program with Gotos is much more readable than trying to do that with functions.

    Also, every function call is a push to the stack, they are not cheap. If you need really fast execution of your code, gotos can actually help you squeeze out that last bit of speed, although this can be at the expense of readabiliy, i’ll agree there.

    Regards Gert-Jan

  34. Lee says:

    > The IL itself does allow it so why not the compiler. Let the programmer be the judge to use it or not.

    Because the compiler must enforce a semantic level of meaning on the code so that it can effectively generate IL code that does what you wrote in the higher level language.

    Consider the difference between for loops and if-else statements. There is quite a bit of difference in the amount of setup required to make each work.

    if-else: No setup required, beyond performing the test condition and branching to the else part. Since there’s no setup, it’s no problem to goto into either the if-body or else-body.

    for loop: At minimum, initializing the loop index and check that it meets the test condition. (foreach is even worse… find the appropriate enumerator, get that all setup, etc., etc…) With all this setup, how do you reasonably do a goto into the body of a for loop AND get provably correct code for EVERY case? Not too likely. (On the other hand, you can goto out of a for loop, because that amounts to little more than a break.)

  35. Gert-Jan van der Kamp says:

    I meant flowchart from Visio to be precise.

  36. StreetUrchin says:

    Nothing like stepping on a setjmp / longjump landmine. I’ve seen some pretty clever exception-like handling built around this construct using C/C++. It drove me nuts till I figured it out. Another developer had called setjmp from main, then whenever his deep library code encountered an error he’d call longjump. The longjump would set the instruction pointer back to the beginning of the program.

  37. Vitaly says:

    What would people say at goto’s funeral?

    goto’s wife: "Oh my sweet goto, I can’t loop without you"

    goto’s kids: "we want our goto back"

    goto’s 3rd cousins’ brother in-laws’ 5th pets’ owner: "He was pure evil, evil I tell you!"

  38. Gabe says:

    I would suggest converting the code to MSIL, then decompiling the MSIL into C#. That way you get C# code, but it will still have loops where ever possible.

  39. This code

    10   J = 2

    20   IF FOO THEN GOTO 50

    30   FOR J = 1 TO 10

    40     PRINT J

    50     PRINT "—"

    60   NEXT

    70   PRINT "DONE"

    can write on C# using new bool variable:

    j = 2;

    bool foo1 = foo;

    if (!foo)

       j = 1;

    for (; j <= 10; j ++)

    {

       if (!foo1)

           print (j);

       foo1 = false;

       print ("—");

    }

    print ("DONE");

    Any code do not repeates twice!

    You can use foo instead foo1, when this variable do not required in other code part.

  40. David W says:

    I don’t think anyone here fails to realize that all flow-of-control structures end up as GOTO’s at a machine level. The point is that the machine can manage the GOTO’s, but for humans its like reading a story, telling someone to jump two pages ahead, then jump three pages back. Yeah, you can do it, but geez, does that make it a good idea? Heavens – the computer can count to a zillion in binary, but that doesn’t mean its a good idea for human consumption.

    That aside, my personal beef isn’t with "goto’s" per se, but when they are being used in obviously lazy situations when just a few minutes’ effort would have created a more streamlined control flow structure. In *most* cases, a GOTO is a hack, an amputation of logic where a few stitches of design and discretion would have avoided an ugly and usually unnecessary scar. I’ve rarely seen a structure made *more* elegant with a blunt GOTO. But that’s just me…

  41. Peter Wone says:

    GOTO is all about sequence in the context of state. Code in this form is inimical to parallelisation.

    This is easy to automate with functional programming languages, where dependencies on evaluation sequence are necessarily explicit. It is damn near impossible to automate in procedural languages where many dependencies are not only implicit but often indirectly implicit (due to side effects).

    When a language requires explicit declaration of dependencies, laziness inhibits their spurious creation. Better quality code results, and it is incidentally more amenable to optimisation for multiple CPUs.

    As in life, time is the great enemy.

  42. I think people are confusing GOTO with branching.

    GOTO is a programming statement which allows unstructured branching. Other programming statements (if-then, for, while, throw) only allow branching within a particular context or programming structure. Unstructured branching allows you to write incomprehensible code *very* easily. For example (using pseudo-basic)

    10 x = 110

    20 if ( x is even ) goto 40

    30 x = 3 * x + 1

    40 x = x / 2

    50 if ( x > 10 ) goto 20

    60 print x

    I mean, never mind what x might be at the end, can we even be sure this will finish for different start values of x?

    (Please don’t get caught up on this being a mathematical example, BTW. Statements 20 to 50 could be totally non maths related – as long as they interfere with each other you are going to get a problem).

    It’s very easy with unstructured branching to start getting this sort of effect. Of course, you could use GOTO to duplicate structured branching (like duplicating a while loop), but why do it? It is far nicer when you come to look at your code to know there are *no* GOTOs in it rather than have to analyse whether each individual GOTO is sensible or not.

    As to the oft quoted example of error handling in a sequence of method calls, I believe this indicates bad design. First of all I think you need to carefully consider what *is* an error, then isolate your error handling in one group of methods or classes or whatever, so that the rest of your code isn’t burdened with constantly having to check whether things are happening ok. i.e., it is better to write:

    method_a()

    {

    method_a_1();

    method_a_2();

    etc

    }

    – than:

    method_a()

    {

    if ( method_a_1() == ok )

    {

    if ( method_a_2() == ok )

    {

    etc

    }}}}}}}}}}}}}}}.

    – or some equivalent using gotos.

    Where you simply are unable to pre-check for an error (like that nuclear refinery you were monitoring has just gone off-line), you should probably use an excepion and exit (gracefully) until somebody fixes the problem.

    Richard

  43. Hugh says:

        for(J = FOO ? 3 : 1; J <= 10; J++)

          PRINT (string.Format("{0}rn—",J));

        PRINT ("Done");

  44. madkat says:

    What I was trying to say is that the code should be refactored properly. Using Goto is ugly and difficult to read. Simply check what the code is trying to achieve and find the best way to replicate that functionality.

    Which you will note was my first suggestion, yes. But what if you have five hundred thousand lines of goto-ridden mainframe code to translate? “Ugly and difficult to read” is better than “not working”, and cheaper and more accurate than “translate five hundred thousand lines of code by hand”. — Eric

    Just because the original code uses a Goto, that doesn’t mean our new code has to use any at all. We could similarly do this:

    int j = FOO ? 3 : 1;
    while (j<=10)
      PRINT (string.Format(“{0}rn—“,J++));
    PRINT (“Done”);

    Using your human intelligence to create a goto-free program that matches the semantics of one particular code fragment is easy. Writing a program that does that to any arbitrary fragment is rather more difficult, I assure you. — Eric

  45. madkat says:

    (with a lower case j in line 3, obviously)

  46. bmann says:

    Your point about the difficulty in understanding convoluted code is well taken.  In fact some of the coded solutions produced wrong results.  In the case where FOO is true they fail to start and end the list with "—".

    Actually, your example and solution point out the fundamental translation problem and solution.  Antique BASIC treated for a FOR loop index as a global variable and the loop condition was checked in the NEXT statement (Always on iteration was executed).  The best way to handle the translation problem is to break the FOR loops into initialization, Value adjustment, and conditional jumps, much like you did ( I would check end conditions at the NEXT statement ).

    There are also wonderful dialect specific factors like what is the value of j after the loop?  Is it 10 or 11?  That would depend on the specific implementation and is unfortunately something that may matter for the code that followed.  After all it was often possible to jump out of FOR loops before termination.

  47. Nick says:

    if (StatusOK) {

      if (DataAvailable) {

         ImportantVariable = x;

         goto MID_LOOP;

      }

    } else {

      ImportantVariable = GetSomeValue();

      MID_LOOP:

      //Lots of code

    }

    I’m disappointed that no-one has mentioned Steve McConnell yet.

  48. madkat says:

    Eric:

    If you have 500,000 lines of working code which is riddled with GOTO statements, and you then replicate it on a line-by-line (or fragment-by-fragment if you prefer) basis, there’s no guarantee that it’s going to work in the target environment. There are other factors such as that pointed out by bmann: The value of J upon exit may be different, which means the code could fail catastrophically at its first run, or even at some later point when FOO eventually does equal True, and then you’d be left with the serious headache of having to debug it. If you untangled it properly, it would make that debugging much more simple and the code would be readable to anyone else who came to look at it.

    Aside from that, if it’s working, why would you move it to another language?

    bmann: Good point… but with our new refactored code we should be able to see exactly where the problem is and what the problem is at aa glance 🙂

  49. Samuel Warren says:

    Seriously, we have methods now…… If you need to jump to something inside a loop, then it should probably be in a separate method.

  50. With regard to Duff’s device (see comments from A.C.Hynes and Matthew Whited above) here is another C# version which is closer to the original.   C# is surprisingly expressive at times:

    namespace DuffsDevice

    {

       using System;

       class Program

       {

           static void Main(string[] args)

           {

               unsafe

               {

                   short[] data = new short[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

                   short register = -1;

                   fixed (short* dataPtr = &data[0])

                   {

                       DuffsDevice(&register, dataPtr, data.Length);

                   }

                   Console.WriteLine(register);

               }

           }

           /// <summary>

           /// C# approximation to Duff’s device.

           ///

           /// void send(register short *to, register short *from, register int count)

           /// {

           ///     register int n=(count+7)/8;

           ///     switch(count%8)

           ///     {

           ///         case 0: do{ *to = *from++;

           ///         case 7:     *to = *from++;

           ///         case 6:     *to = *from++;

           ///         case 5:     *to = *from++;

           ///         case 4:     *to = *from++;

           ///         case 3:     *to = *from++;

           ///         case 2:     *to = *from++;

           ///         case 1:     *to = *from++;

           ///         }while(–n>0);

           ///     }

           /// }

           /// </summary>

           /// <param name="to"></param>

           /// <param name="from"></param>

           unsafe static void DuffsDevice(short* to, short* from, int count)

           {

               int n = (count + 7) / 8;

               switch (count % 8)

               {

                   case 0:

                       *to = *from++;

                       goto case 7;

                   case 7:

                       *to = *from++;

                       goto case 6;

                   case 6:

                       *to = *from++;

                       goto case 5;

                   case 5:

                       *to = *from++;

                       goto case 4;

                   case 4:

                       *to = *from++;

                       goto case 3;

                   case 3:

                       *to = *from++;

                       goto case 2;

                   case 2:

                       *to = *from++;

                       goto case 1;

                   case 1:

                       *to = *from++;

                       if (–n > 0) goto case 0; else break;

               }

           }

       }

    }

  51. Brian Smith says:

    re: Duff’s Device… Hand-rolled optimization in C#? You guys are funny.

  52. Turns out that a simple loop to iterate through a safe array can be a bit faster than my version of Duff’s Device in .NET.   A loop to iterate through allocated stack space (using stackalloc) using an unsafe pointer is much faster.   So, ‘Duff’s device’ in C# is sub-optimal.   A case of hand-rolled de-optimization!   Full marks to C# for being so expressive, but don’t use the technique!

  53. Farrukh says:

    this is funny stuff.

    We are being guided to the old, frustrating, spider webs of looping with GOTOs.

    this shouldnt practically be an approach in professional development using C#.

  54. Bryan says:

    One time long ago I inherited a program written in C-tran.  The author knew and thought in FORTRAN but had to code the app in C, and a veritable mess of code resulted that contained over 400 GO TO stetements.   We stumbled along maintiaing it, never given the time to rewrite what was "working" but always allowed the time to analyze the mess of spaghetti for unintended consequences of the changes we were planning to make (and deal with the ones we did not foresee).

    We recruited a bright guy from the customer support team to come into the product development team and his soel condition for accepting the position was they he be allowed to rewrite that app.  It was accepted and the final product after3 months was easier to understand, easier to maintain and easier to extend.

    GOTO is just a tool – but it is VERY dangerous in the hands of those who do not fear it.

  55. Kevin says:

    Bad code is bad code. One needs to understand what branching into a FOR statement in their compiler means. I have used languages where there is only the goto.  I have also see bad FOR statements.

    10 FOR i = 1 TO 10

    20     PRINT i

    30 NEXT i

    40 LET i = i * 2

    50 PRINT i

    What is the value of i? 20 or 22.  This depends on the BASIC version.

    Of course we should not use i outside to loop.

  56. Gene Naden says:

    Reading most of this thread, I was amazed to discover how interesting it is to look at GOTO from 20 or 30 different points of view.

    Getting back to the question that started this thread: the reason she/he wants to convert the old BASIC code to C# is (presumably) so that it will use the .NET CLR and interoperate with other .NET code. The problem is a kind of "impedance mismatch" meaning that BASIC is so dumb, and C# is so smart, that conversion is impractical. What we need is a cruder version of C# (call it "C-dumb") that is closer to the BASIC code. Has anyone considered FORTRAN?

    Seriously, I once had to write a state machine once to handle Asterisk telephone events and it was a heck of a lot easier to write, read and modify using a few GOTOs versus keeping it "pure" with strange WHILEs.

    The argument that MSIL uses GOTO so we should use them too is suspect. Consider writing a specification for a steel screw. Yes, it is made of molecules but when you order a certain screw do you really want to describe how all the molecules relate to one another? It is the wrong level of abstraction.

    Maybe God Almighty will write the answer with fiery letters in the sky: "GOTO IS/IS NOT HARMFUL!"

  57. Clyde Coulter says:

    How much knowlege is available about how the original program works, or (more importantly) what it is supposed to be doing?

    A lot of old code can be reduced (in lines of codes) by 20 to 80%, purely on the basis that much of it was cut/pasted from other code that did the same thing on a different instance of data.  This is why classes/objects/interfaces/etc came about to begin with.

    I agree it is painful to take in hand thousands of lines of code and re-design and re-write it, but it many cases it is well worth it, and would take a lot less time than one might think (there is a certain moment of inertia that begins to build once you get familiar with a coding style no matter how ugly it might seem).

  58. Itai says:

    For the love of god!!

    Why would you do a direct translation of the code? Just use a loop and some if conditions in it to skip sections.

    DO NOT USE GOTO!

    Why? Well, suppose you have a million lines of code to translate. Your choices are (1) spend 10 hours writing a literal translator that generates ugly code, (2) spend 10 hours writing a literal translator and then 90 hours rewriting all the code that involves gotos, or (3) spend 10000 hours rewriting the whole system from scratch. The costs of those three choices are $1000, $10000 and $1000000, respectively. Suppose you have to pay for it. Which would you choose? How much are you willing to spend on beautifying code that already works just fine? — Eric