Double-Dummy Bridge Program with and without Goto

Someone accepted the challenge to rewrite the Double Dummy Solver readably without 'goto' and posted pseudo-code for that Solver in a Usenet discussion group. I've modified his code somewhat (but will call it "George's code" for convenience) and have converted my own code to pseudo-code in a similar format, so we can compare ``apples with apples.'' The low-level processing in his code is identical to that of mine; it's just the looping controls that are rewritten and stripping the routines down to ``pseudo-code'' makes it easy to focus on the differences. The ``pseudo-code'' looks very much like C language, though of course it won't compile.

I've never denied that goto's are bad. The point is that other things (longjmp(), redundant tests, break, inside-loop state changes, etc.) are also bad to varying degrees and one seeks compromise.

In the goto for backtracking used in the Double Dummy Solver, the goto seems horrendous at first, but objective study reveals that it has its own strict and elegant structure, albeit a highly non-standard one.

If we strip out the code sections which are identical, in the two versions, we see exactly the difference between James' code and George's code. Here's what we see.

James' code:

The four Iterate's each have a very natural meaning: loop through players or loop through tricks. (There are four Iterates instead of two, because sometimes we need to iterate backwards.)

George's code:

Exiting in the middle of the function is not a big fault, but my exit at the end does help demonstrate the smoother elegance of my control structure. Similarly, that I initialize `Trick' once, but George has to replicate this code isn't a big deal but, again, illustrates that my code represents the more natural structure for the problem. George's if (condition)'s, advances's, and regresses's just do what I do with
    for (; condition; advance)

Here's one of my for statements (the real code, not pseudo-):


       for (numcard = 0, player = P->Leader = trickwinner;
                     numcard < NUMP;
                     numcard++, player = LHO(player)) {
            ... /* Handle_card */
       }

It suffers the moot fault of cramming logic into a for header, but still seems self-explanatory: We're looping through the NUMP players, starting with the Leader who is the previous trickwinner.

My four for loops employ no break's or continue's whatsoever. The explicit looping controls in the for header make the logic quite transparent.

George couldn't use such for statements -- he'd end up with my goto, or C's non-existent break 2. So he ends up with two for (EVER) loops inside yet a third for (EVER) ! The looping controls I give explicitly in the for header become, in George's code, inside-loop conditional state changes.

Some for (EVER) loops make sense and are proper code. But ``nothing is forever'' and for's are usually more readable when the termination condition is coded normally. To me it seems questionable to claim that using no less than three such for (EVER) loops along with the necessary break's, if's and state changes just to avoid a a single goto improves the program structure. I'm interested in what others think.

Please compare the two fragments and tell me which is ``better'' or ``more readable.'' I prefer mine, but am sincerely curious what others think.


    /* James' code */
    Initialize;
    ITERATE through tricks until outcome is decided {
        Set trick to empty;
        ITERATE clockwise through players {
            Determine available legal plays;
          try_again:
            Choose a legal card, and play it to trick;
        }
        Determine trick's winner, adjusting score;
    }
    ITERATE through tricks backwards until done {
        ITERATE counterclockwise through players {
            Retract played card;
            If (retracted play was a failure)
                    && (alternatives remain) {
                GOTO try_again;
            }
        }
    }
    Print solution and exit;



    /* George' code */
    Initialize;
    Set trick to empty;
    ITERATE FOREVER {
        ITERATE FOREVER {
            Determine available legal plays;
            Choose a legal card, and play it to trick;
            If (trick complete) {
                Determine trick's winner, adjusting score;
                If (outcome decided) {
                    BREAK;
                }
                ADVANCE STATE to next trick;
                Set trick to empty;
            } Else ADVANCE to next player;
        }
        ITERATE FOREVER {
            If (trick empty) {
                If (done) {
                    Print solution and exit;
                }
                REGRESS STATE to previous trick;
            } Else REGRESS to previous player;
            Retract played card;
            If (retracted play was a failure)
                    && (alternatives remain) {
                BREAK;
            }
        }
    }

Which code is more readable?

People rightly complain that the problem with goto is the need to grok all references to the associated label but, in any non-trivial case, isn't an editor search for all occurrences of that label the first thing you do? (No one's trying to defend spaghetti code containing a maze of goto's.)

My point isn't to offer a quantitative metric comparing my `goto' with the hard-to-grok parts of George's code, but just to claim that open-mindedness is superior to dogmatism.


Go back to Lesson 9.
Please send me some e-mail.
Go back to my home page.