I'd Consider That Harmful, Too

Graham Stewart,

C#:

switch( k )
{
case 3:
System.Diagnostics.Debug.Print( “case 3” );
goto case 6;
case 6:
System.Diagnostics.Debug.Print( “case 6” );
break;
}

compiled IL result:

L_000f: ldstr "case 3"
L_0014: call void [System]System.Diagnostics.Debug::Print(string)
L_0019: nop
L_001a: br.s L_001c
L_001c: ldstr "case 6"
L_0021: call void [System]System.Diagnostics.Debug::Print(string)
L_0026: nop
L_0027: br.s L_0029

I draw your attention notably to the 2 “br.s” instructions, each of which is an unconditional jump (goto) to the VERY NEXT instruction (fall-through). Both occurences are superfluous; the code does not change meaning AT ALL when these instructions are replaced with “nop”.

And you conclude that C/C++ is the evil version?

Which of the following 2 conditions does your user most care about:

  • A program that is responsive, or
  • A program whose source code is “pretty”

You can argue the merits of beautiful code all day, but be careful not to lose sight of the user; THEY are your ultimate critic.

Jim: “I’ve never seriously missed GOTO in Java.”

I do right now, writing a little code generator. As it seems I need to rely on javac doing some heavy common tail combination. Missing the comma operator, too.

Wirth is just awesome. That’s all I can say :slight_smile:

mccoyn:

Agreed, I am still testing twice. But if the goal is to improve code readability (which was your stated reason for using GOTO) then I find my approach more readable and maintainable. The ‘for’ line clearly states the possible exit conditions, rather than burying them in the body of the loop.

Andrew R:

My focus IS the user and I’d be prepared to bet that the user would rather have a (marginally) slower program with fewer bugs.

You’re right of course, the IL output isn’t very clever there. But that is a limitation of a dumb compiler that isn’t doing a very good job of optimising. It is not a fault of the language construct itself.

And realistically, how many picoseconds do these “superfluous” breaks add?
I can’t see their inclusion altering the responsiveness of a program in any significant way. If my application was that time-critical then I wouldn’t be using managed code in the first place.

The reason I said that the C/C++ approach to switch is evil, is that it defaults to falling through and 99% of the time when I write a switch case, I don’t want it to fall-through.
Therefore omitting a break and allowing fall-through would be a bug in 99% of the switch cases I write. In other words, it defaults to a bug.

(This is something Jeff touched on in his post called “Falling into the Pit of Success” http://www.codinghorror.com/blog/archives/000940.html )

On the rare occasion that I do want to fall-through, then I have to add a comment indicating that I have deliberately omitted break, otherwise a future maintenance programmer is likely to “correct” it.

C# on the other hand, prevents you from falling-through without explicitly declaring your intent to do so. It defaults to preventing a bug.

Furthermore it enhances maintainability by allowing each switch-case to be self-contained. You can introduce new cases and re-order the existing ones without breaking anything (try that when you are using fall-through code in C).

The C# approach also simplifies more complex cases where there are multiple fall-throughs. Like this:

switch ( flavour )
{
case PearApple:
System.Diagnostics.Debug.Print( "Pear And " );
goto case Apple;

case OrangeApple:
System.Diagnostics.Debug.Print( "Orange And " );
goto case Apple;

case Apple:
System.Diagnostics.Debug.Print( “Apple” );
break;
}

Someone should tell the Codebetter.com folks about writing persuasive articles instead of insulting everybody that’s not part of their cult.

foobar on October 25, 2007 04:44 PM

As a current member of Codebetter I sympathize with your view. Take heart that the entire staff should not be painted with that brush and that several of us are launching a new blog site without the vitriol soon.

I sincerely hope that the community will have an open mind and realize that the views of one are not the views of all.

Can I point out for the umpteenth time, the actual statement was “Non-local gotos considered harmful!” Think setjmp(), longjmp(). Why discuss using a goto to simulate standard control structures? That was not the point of the article.

Multiple returns rules! Guard clauses, dispatch methods… I love it!

As soon as you’re using conditionals (which, granted, [http://catpad.net/michael/apl/ isn’t always the case]) multiple returns will probably be useful.

Death to the cargo cultish idiom of
int some_function(boolean val) {
int result = 0;
if (val) result = 3; else result = 4;
return result;
}

Terrier:

The text of the Dijkstra article is linked to by Jeff at the start of his post.
If you want a more authoritative source then the original article is available in the ACM archives at http://doi.acm.org/10.1145/362929.362947

It is entitled “go to statement considered harmful”, no mention of “non-local” there.

Although Dijkstra does discuss the problems with using goto in the new and crazy world of procedures, he also mentions the problems with using goto in “repetition clauses (like, while B repeat A or repeat A until B)”.

Also the discussions above are not about “using a goto to simulate standard control structures”, they are about whether it is ever valid to use goto to short-circuit such structures.

Did you mean 1986 or really 1968? Seems a little strange that the response to the original article would take so long to appear…and did they even have goto statements in '68?

Also the discussions above are not about “using a goto to simulate standard control structures”, they are about whether it is ever valid to use goto to short-circuit such structures.

Well put Graham.

Gotos are a low level building block. When you can use a higher level control structure it will be more easily understood and you should do it. When none of the control structures fit your needs you must roll your own and goto allows this in the simplest possible way.

Why not try Haskell and get pure, statically-checked, first class GOTO statements by way of continuations? They’re also frightfully hard to understand which works as a nice kind of low-pass filter: if you’re a good enough programmer to understand them, you’re probably good enough to use them appropriately, too.

David: yes Dijkstra’s original letter was published in March 1968.
The letter is seen by many as the beginnings of structured programming.

And yes, they did have GOTO in 1968!
In fact the point was that they didn’t much else when it came to controlling the flow of the program.
Even such basics as iterative loops were typically implemented using GOTO.

if you’re a good enough programmer to understand them, you’re probably good enough to use them appropriately, too.

And what about the lowly maintenance programmer who picks up your code in two years time?
Making his job easier should be more important than writing “clever” code.

Though the 1949 example is cute, the use of “considered harmful” in the headline of a major newspaper is pretty rare. My search on the historical New York Times, Wall Street Journal, Chicago Defender, Los Angeles Times, and Washington Post (via ProQuest Historical Newspapers) turns a mere EIGHT headlines with the words “considered harmful” in them from the 19th through the 20th centuries.

Of those, only the 1949 is a pure case of “X considered harmful” without anything else. Here are the headlines:

DOOM OF TYPHOID.; Discovery Made at Washington. Large Bodies of Water Can be Readily Sterilized by Solution of Copper. Cholera Bacteria May be Exterminated as Well in Three Hours Time. Preparation Not Considered Harmful to Man or Beast Incidental Agent.
Los Angeles Times (1886-Current. May 9, 1904. p. 1

PENDING RAILWAY BILLS NOT CONSIDERED HARMFUL; Corporation Lawyer Says Elimination of Stock and Bond Feature and Other Changes Remove Radical Features–Security Supervision.
Wall Street Journal (1889-Current file). New York, N.Y.: May 25, 1910. p. 2

Letters to The Times; Pump-Priming’ Is Upheld Under Present Conditions, Second Try Might Be Successful Basis of the Theory Unintegrated Policies Broadening Citizenship Oath Quebec’s Civil Code Sources Evil Seen in Monopolies They Are Considered Harmful Both to Production and Distribution Financing the Retailer Quarantine Move Opposed New Traffic System Wanted DOGWOOD
New York Times. Apr 22, 1938. p. 18

Single Tax Seen Danger; Resolutions Oppose Measures Considered Harmful to Realty
Los Angeles Times (1886-Current File). Los Angeles, Calif.: Oct 30, 1938. p. E2

Rent Control Controversy; Enacting Now of Hasty Legislation Considered Harmful
ROBERT S. FOUGNER… New York Times (1857-Current file). New York, N.Y.: Aug 19, 1949. p. 16

CONSIDERED HARMFUL; Palm Springs Schools to Outlaw Sororities
Los Angeles Times (1886-Current File). Los Angeles, Calif.: Apr 15, 1960. p. A7

Experts Call for Balance In Helping Young Cope; Dwelling on Negatives Considered Harmful
The Washington Post (1974-Current file). Washington, D.C.: Jan 31, 1986. p. A12

Physicians, in Film, Decry Embargo’s Effect on Iraqi Children; The shortage of medical supplies is considered harmful to innocent victims. A Stony Brook doctor, a priest and a controversial documentary.
By MARJORIE KAUFMAN. New York Times (1857-Current file). New York, N.Y.: Dec 27, 1992. p. LI10

I know, you were really curious, right? :slight_smile:

2c

  • I use gotos, but only to have some sort of exceptions in C, i.e. in a structure like:
    if test_1 goto handling_1;

    if test_n goto handling_n;

handling_n: deallocate and other stuffs

handling_1: deallocate and other stuffs

Exceptions would do the job in this case, but again in C I feel this is the cleanest way to handle errors properly

Another cent on COMEFROM: looks like hooks in xemacs lisp to me or, to be more modern, to the attachment of aspects to a given program…

The main point of Dijkstra was that with a goto in the code, you can’t proof mathematically that the code is correct. That’s still true today in OO languages.

Nonsense.

Let’s assume your program is a sequence of pairs consisting of statements and a list of conditional jumps (that is, switch { case a: goto A; case b: goto B; etc… }), all finishing off with otherwise: goto next statement.

What’s true before a given statement S is the conjunction (AND) of all the conditions that lead to a jump to that statement. From that, prove what you can (or need) about what’s true after statement S, and then analyze where S can in fact jump to.

There’s a start of a proof system. It probably needs to be developed a bit, but you can certainly prove things even with goto statements in your code.

And automatic program proving (in the general case) is impossible for anything that’s turing complete, independent of whether there’s goto statements or not.

Goto is alive and well in C#.

I’ve seen this in a current code base:

(psuedocode)
clptryagain:

try
{
//Do something
}
catch
{
retrycount++;
if (retrycount = maxretries)
{
goto clptryagain;
}
}

I thought I buried goto for good in VB6 code but apparently it exists in C# as well. The horror, the horror…

Does anyone know why it was included in C#?

Also, check this out:

A goto statement is executed as follows:
2 If the goto statement exits one or more try blocks with associated finally blocks, control is initially transferred to the finally block of the innermost try statement. 3 When and if control reaches the end point of a finally block, control is transferred to the finally block of the next enclosing try statement. 4 This process is repeated until the finally blocks of all intervening try statements have been executed.
5 Control is transferred to the target of the goto statement.

Also I found this GEM on MSDN:

http://msdn2.microsoft.com/en-us/library/13940fs2(VS.80).aspx

// statements_goto.cs
// Nested search loops
using System;
public class GotoTest1
{
static void Main()
{
int x = 200, y = 4;
int count = 0;
string[,] array = new string[x, y];

    // Initialize the array:
    for (int i = 0; i  x; i++)

        for (int j = 0; j  y; j++)
            array[i, j] = (++count).ToString();

    // Read input:
    Console.Write("Enter the number to search for: ");

    // Input a string:
    string myNumber = Console.ReadLine();

    // Search:
    for (int i = 0; i  x; i++)
    {
        for (int j = 0; j  y; j++)
        {
            if (array[i, j].Equals(myNumber))
            {
                goto Found;
            }
        }
    }

    Console.WriteLine("The number {0} was not found.", myNumber);
    goto Finish;

Found:
    Console.WriteLine("The number {0} is found.", myNumber);

Finish:
    Console.WriteLine("End of search.");
}

}

Jon Raynor

@Jim Conyngham, that is even worse than I thought. Young naf that I am, I was simply imagining BASIC and C with loads of GOTOs being hacked in rather than doing what might be called refactoring now. And of course Wirth would have been pleased to show his own languages in a good light. It is all to easy to forget that the world was so different before MS and Borland started making their IDEs with a single keystroke to compile, link and build. Your do…while pattern is very perlish.