goto instruction
-
- Member
- Posts: 255
- Joined: Tue Jun 15, 2010 9:27 am
- Location: Flyover State, United States
- Contact:
Re: goto instruction
I have but one C goto in my entire OS project, in an implementation of vsprintf, and I could easily remove it. It's just not needed for a higher-level language like C that provides constructs like if statements.
While I don't think that goto is inherently evil, I feel it is not necessary for 99% of code, and it really is detrimental to readability. Even in systems-level programming, I believe the two most important considerations should be robustness and maintainability, and that performance is secondary to those. Not to mention modern C compilers are really good at optimization (inline functions)and the speed boost gained by replacing an if statement here or there with a goto would be minimal.
While I don't think that goto is inherently evil, I feel it is not necessary for 99% of code, and it really is detrimental to readability. Even in systems-level programming, I believe the two most important considerations should be robustness and maintainability, and that performance is secondary to those. Not to mention modern C compilers are really good at optimization (inline functions)and the speed boost gained by replacing an if statement here or there with a goto would be minimal.
Re: goto instruction
It doesn't matter that much, the compiler can, and it often does:Solar wrote:inline...turdus wrote:Your code (which is good and readable solution) has a disadvantage that you introduced plus stack handling...
- inline a function which wasn't marked as inline
- not inline a function marked as inline
I think he meant call and ret, bl and bx, etc.Solar wrote:Nope, I copied your example exactly, including the check on expr1 and expr2....and two more branches.
By the way: if goto is soooooo evil, then what about continuations?
[1] Did you all notice? It's not about goto at all. In well-written code there are no gotos, just because they're not necessary.
Re: goto instruction
Both "break" (outside a switch-case construct) and "continue" break the control flow. (Again, drawing a NSD makes this obvious.)Fanael wrote:By the way: if goto is soooooo evil, then what about continuations?
The "continue" keyword usually points to a suboptimal algorithm, and can often be avoided with some simple code rearrangement. However, sometimes it does make things much easier. (I used "continue" in two places in PDCLib, one of them the malloc() test driver, the other being strtok() which is pretty convoluted anyway.)
The "break" keyword, on the other hand, is quite similar to goto in terms of evilness: You introduced a loop, including a condition on which the loop may be terminated - and then introduced another terminating condition within the loop. Someone quickly browsing your code might have missed the "break" and continue working on false assumptions. (Needless to say, there are no non-case "break"s in PDCLib source, just like there are no "goto"s.)
Gee, I just found this in the Pro-POS Style Guide of old:
3.4 goto, continue, break
Do not use goto, period.
Do not use break anywhere else than to end a case block, period.
Try to avoid continue where possible.
These three basically break structured programming. You will see if you ever attempt to express a control flow containing any of those in a Nassi-Shneiderman diagram. continue is a little less condemnable since it at least honors the loop condition.
Instead, consider:
If using option 3), do not forget to check the return value.
- redefining your algorithm so that the goto / break / continue becomes unnecessary;
- using if-else;
- putting the code in a subroutine, "breaking" from it with a return.
Every good solution is obvious once you've found it.
Re: goto instruction
But neither break nor continue have anything to do with continuations.
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
Re: goto instruction
And continuations have nothing to do with goto.
Re: goto instruction
Huh?
If you are asking about setjump() and longjump(), begone afore I find my mighty foam cluebat.
If you are asking about setjump() and longjump(), begone afore I find my mighty foam cluebat.
Every good solution is obvious once you've found it.
Re: goto instruction
I'm asking about real continuations, not about that heinous imitation.
Some people would not agree.Combuster wrote:And continuations have nothing to do with goto.
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
Re: goto instruction
Continuations are references to (the remaining steps of) an algorithm. They are not control flow instructions, and therefore offtopic. More importantly, its not part of standard C, and the language doesn't sanely implement it either.
I would love to discuss it though - its much less religion-sensitive than "goto", but a moderator would have to split the thread first in that case.
I would love to discuss it though - its much less religion-sensitive than "goto", but a moderator would have to split the thread first in that case.
Re: goto instruction
When I say "continuations", I mean "continuations and related things", which includes among other things call/cc, which is a control flow instruction, so it's only a slight off-topic at most. I agree a thread split would be a better idea than continuing here nevertheless.
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
Re: goto instruction
I hope this example is suitable enough just to give you some food for though.
Instead of writing something like this:
I'd always prefer this:
Instead of writing something like this:
Code: Select all
int func(int x)
{
int result = x;
if (x > 1) {
if (x > 2) {
if (x > 3) {
if (x > 4) {
if (x > 5) {
if (x > 6) {
if (x > 7) {
if (x > 8) {
if (x > 9) {
result += x * 3 + 8;
}
result -= 3;
}
result += 5 * 9 * x;
}
result -= 9 * x;
}
result *= 3 * x;
}
result -= 5 * 6 * 7;
}
result -= 7;
}
result *= 2 * x;
}
result /= 3;
}
result *= 25;
return result;
}
Code: Select all
int func(int x)
{
int result = x;
if (x < 10) {
goto over_10;
}
result += x * 3 + 8;
over_10:
if (x < 9) {
goto over_9;
}
result -= 3;
over_9:
if (x < 8) {
goto over_8;
}
result += 5 * 9 * x;
over_8:
if (x < 7) {
goto over_7;
}
result -= 9 * x;
over_7:
if (x < 6) {
goto over_6;
}
result *= 3 * x;
over_6:
if (x < 5) {
goto over_5;
}
result -= 5 * 6 * 7;
over_5:
if (x < 4) {
goto over_4;
}
result -= 7;
over_4:
if (x < 3) {
goto over_3;
}
result *= 2 * x;
over_3:
if (x < 2) {
goto over_2;
}
result /= 3;
over_2:
result *= 25;
return result;
}
- Brynet-Inc
- Member
- Posts: 2426
- Joined: Tue Oct 17, 2006 9:29 pm
- Libera.chat IRC: brynet
- Location: Canada
- Contact:
Re: goto instruction
This thread is boring.
Re: goto instruction
"... and asked me whether I thought I was smarter than all these programmers out there who say goto is bad ..."gerryg400 wrote: nobody said that using goto was related to intelligence or badness ...
Most of the comments were about this particular example ...
And the OP's examples were clearly never intended to be thought about literally -- it was only a generic thought experiment. Taking it literally is silly and completely misses the point!
I think the quote is unwise. Any fool can write code that a computer can understand. It takes someone smart to make code that a computer can run efficiently. Any fool can also write code that a human can understand which runs inefficiently. It takes someone very very smart to write code that runs efficiently, and is readable by humans.Solar wrote: Martin Fowler wrote:
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand."
Once again, you are taking things too literally. I was speaking in a more generic sense. It's the basic attitude that "I shouldn't code for what the computer does easily, I should code for what a human can read." That's not "good programming". That's the philosophical basis of fatware.Solar wrote: do you really believe what you just said? That software today runs "so slow" because people no longer use 'goto'?
"These three basically break structured programming."
Anyone who can draw a Nassy-Shneiderman diagram knows what I mean.
I claim that you are under the misimpression that C is a structured language. The fact that it contains 'goto' is proof enough that it is not. The fact that you can torture and abuse the language into behaving like a structured language does not make it one. Mistakenly believing that C is a structured language is the religious basis of these discussions.
Re: goto instruction
I have an example where I like to use goto (and I think I´ve seen it in Linux too) for not making too much failures.
This will lead to smaller code and you will make less failures, because you´ve forgotten to update all if-code-ways.
Code: Select all
int foo() {
step;
if(something)
goto error1;
if(somethingOther)
goto error1;
if(somethingStupid)
goto error2;
step;
return bar;
error2:
step;
error1;
step;
error0;
return error;
}
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
Re: goto instruction
I'm not in favor of using goto to jump back and forth. I would never use it to jump backward. It's just for the purpose of skipping some parts of my code.
And I fervently claim it SHOULD always be used to leave a function early. I find it absolutely confusing to see functions with several returns all over the place, because whenever later you need to add cleanup code to your function, you have to look at all of these returns. In fact, the very first lines I write when coding a new functions are these (ALWAYS):
So when I later add dynamically allocated variables to my function, all I have to do is something like this:
Of course I have to be careful to assign NULL whenever I free my dynamic variables in the course of the function. I've taken this to the point where I find it the only acceptable situation where 2 statements may go on the same line - freeing and assigning NULL as in:
But normally I don't free them before finish; instead I'd just leave x allocated until the end of the function; so "finish" is for me something like a garbage collector.
Only when I allocate my variable several times in the function, as in a loop, where I always make sure the "free()" is done RIGHT at the start of the loop:
So now the benefit of using goto is that whatever happens, I can leave my function early and be sure I free all my variables:
Just to counter some possible objections: It's also part of my convention to declare ALL variables at the start of the function and to initialise them with some default value (NULL, 0, etc).
And I fervently claim it SHOULD always be used to leave a function early. I find it absolutely confusing to see functions with several returns all over the place, because whenever later you need to add cleanup code to your function, you have to look at all of these returns. In fact, the very first lines I write when coding a new functions are these (ALWAYS):
Code: Select all
int func(params...)
{
int result = 0;
//TODO
finish:
return result;
}
Code: Select all
int func(params...)
{
int result = 0;
mytype_t *x = NULL;
//TODO
finish:
if (x != NULL) {
free(x);
}
return result;
}
Code: Select all
int func(params...)
{
int result = 0;
mytype_t *x = NULL;
//some code
x = malloc(sizeof(mytype_t));
//some more code
free(x); x = NULL;
finish:
if (x != NULL) {
free(x);
}
return result;
}
Only when I allocate my variable several times in the function, as in a loop, where I always make sure the "free()" is done RIGHT at the start of the loop:
Code: Select all
int func(params...)
{
int result = 0;
mytype_t *x = NULL;
for(;;) {
if (condition) {
break;
}
if (x != NULL) {
free(x); x = NULL;
}
x = malloc(sizeof(mytype_t));
//do something with x
}
finish:
if (x != NULL) {
free(x);
}
return result;
}
Code: Select all
int func(params...)
{
int result = 0;
mytype_t *x = NULL;
for(;;) {
if (condition) {
break;
}
if (x != NULL) {
free(x); x = NULL;
}
x = malloc(sizeof(mytype_t));
//do something with x
if (some error detected) {
//don't have to care about any allocated variables lying around, "finish" will take care of them
goto finish;
}
}
finish:
if (x != NULL) {
free(x);
}
return result;
}