GOTOphobia considered harmful in C
blog.joren.ga
GOTOphobia considered harmful in C
1–10 of 319 posts
Re: GOTOphobia considered harmful in C
#2Nowadays there's more consideration given to structured programming and that's a good thing but that doesn't necessarily mean that GOTO should never be used—and if it is then it doesn't mean the whole structure of one's program ought to be called into question.
No doubt GOTO can be dangerous and can lead one into bad habits but in certain instances it can simplify code and make it less prone to introduced bugs. Modern coding practice teaches us to recognize and avoid spaghetti code so with those constraints in a programmer's mind he/she should be able to use GOTO effectively and with safety.
The key issue is to know when it's appropriate to use it and when not to.
Re: GOTOphobia considered harmful in C
#3Re: GOTOphobia considered harmful in C
#4The same is true of while loops. Aside from a few cases where they are required, they are always better rewritten with a less primitive operator (for, etc). The arguments that programmers today make in defense of while are quite similar to the arguments programmers used to make in defense of goto.
Re: GOTOphobia considered harmful in C
#5I've been reading a lot about retro gaming lately, so I'm just thinking in the context of bedroom coders of the 80's that learned to program in BASIC, then moved on to assembly to get more performance, and then later moved on to C and C++ as projects became more complicated. They all seem to have turned out okay.
I suppose what I'm getting at is you can write bad code in any language.
Re: GOTOphobia considered harmful in C
#6 0:[0226:084752]:sun-go:~/txr$ git grep '\ ' '*.c' '*.h' '*.l' '*.y' | wc
402 1386 12866Re: GOTOphobia considered harmful in C
#7The problem with goto is that it is an unbelievably primitive operator. It can be used to implement any logic at all, and therefore it does not express any logic very clearly. It's a bad way to express intent in code. Aside from the exceptions discussed in the article, there is always a better, clearer way to express logic than to use goto statements. The same is true of while loops. Aside from a few cases where they…
E.g. even an odd problem. Let's use GNU C with local functions:
#include
bool even(int x)
{
auto bool odd(int x);
bool even(int x)
{
if (x == 0)
return true;
else
return odd(x - 1);
}
bool odd(int x)
{
if (x == 0)
return false;
else
return even(x - 1);
}
return even(x);
}
Using goto: achieved by a mechanical transformation involving just some local edits: bool even(int x)
{
goto start;
even:
{
if (x == 0)
return true;
else
{
x = x - 1;
goto odd;
}
}
odd:
{
if (x == 0)
return false;
else
{
x = x - 1;
goto even;
}
}
start: goto even;
}
Every tail-called local function just becomes a block headed by a goto label. The tail call is replaced by assigning a new value to every argument variable and performing a goto. Someone who is briefed on the approach here can easily see the original tail recursion and maintain the code in such a way that the tail recursion could always be recovered from it.There was a discussion several years ago in comp.lang.c where a problem was proposed: using whatever approach you see fit, write a C program which strips comments from C code, but preserves everything, including preprocesor directives. Something like that. The person who proposed the problem refrained from posting his solution for several days. He used tail recursion for the entire state machine of the thing (even avoiding if statements; all the cases in the tail functions were handled by the ternary ?: operator).
Others used structured programming: nested loops and such. My solution used goto.
I argued that the goto solution had all the good properties of the superior tail calling solution.
I then supported my argument by writing a text filter which converted that person's tail call program into one with a big function containing goto blocks (compiling and producing the same result and all). A reverse filter would be possible also.
I believe that we can take any mess of a goto graph, divide it into the labeled nodes, round up the variable and everything being done to them and express it as tail recursion. Ironically, the one thing that will make it a bit harder is structured control flow constructs like while, for, switch and what not, where we may have to rewrite those to explicit goto first! E.g. if we look at a while loop, it's like a tail call, but one which is invisible. The end of the while loop body invisibly tail calls to the start, which is bad for understanding.
The thing that will detract from the ability to understand the tail call graph is excessive parameters. In the worst case, every tail function will have to take all of the state variablews as parameters, and pass them all to the next tail function (except for altering some of them). There is a pass that can be done over that to reduce some of these. Like if some tail function foo(a, b, c, d, e, f) doesn't do anything wiht c d e f other than pass it to children and none of those children do anything with those variables (transitively), we can cull those parameters from foo and all the children. This is the hard thing to understand in goto graphs: which of the numerous state variables are relevant to where the goto is going?
Some state vars can be replicated and localized. E.g. in our even() example, we can do this:
bool even(int x)
{
// params of even:
int x0;
// params of odd
int x1;
goto start;
even:
{
if (x0 == 0)
return true;
else
{
x1 = x0 - 1;
goto odd;
}
}
odd:
{
if (x1 == 0)
return false;
else
{
x0 = x1 - 1;
goto even;
}
}
start:
{
x0 = x;
goto even;
}
}
Now we no longer have the same variable on both sides of an assignment. Each block works with its private parameter variable. The other block only every assigns to that variable when simulating parameter passing: e.g. the odd block assigns to even's x0 just before goto even.We can start with a goto graph and make incremental improvements like this and recover a tail call graph. We can then try to understand what the tail functions mean in terms of recursion and document that.
Re: GOTOphobia considered harmful in C
#8Re: GOTOphobia considered harmful in C
#9Re: GOTOphobia considered harmful in C
#10This person is living in a pretend bubble that isn't grounded in the reality of large projects, multiple team members, deadlines, changing requirements, etc.
No programmer is perfect. And when your tool can cut your arm off, you should be careful or route around the dangerous bits when possible.