Ask HN: Why does Linux Kernel use goto statements?
I noticed this goto statement while going through the kernel code. Why is it there and isn't it an indication of bad design? https://github.com/torvalds/linux/blob/19901165d90fdca1e57c9baa0d5b4c63d15c476a/kernel/acct.c#L490
18 comments
Not every use of goto is a sin, at least according to Linus.
How would you write it without goto? Duplicate the code at the bottom, then return? Abstract what is clearly part of that function, into a new function, pass acct to it, call it twice? Neither seems much better to me. And both lead to multiple return statements in the function, which is also considered poor style by some.
Goto common code at the end of a function, such as error handling or clean-up, is idiomatic C. Often where you'd use an exception or conditional execution, in another language. I mostly avoid it myself. Outside of that use, it's probably most common in the drivers as a way to simply implement a state machine.
How would you write it without goto? Duplicate the code at the bottom, then return? Abstract what is clearly part of that function, into a new function, pass acct to it, call it twice? Neither seems much better to me. And both lead to multiple return statements in the function, which is also considered poor style by some.
Goto common code at the end of a function, such as error handling or clean-up, is idiomatic C. Often where you'd use an exception or conditional execution, in another language. I mostly avoid it myself. Outside of that use, it's probably most common in the drivers as a way to simply implement a state machine.
> "...isn't it an indication of bad design?"
No. See https://en.wikipedia.org/wiki/Goto#Common_usage_patterns It's still used in systems programming contexts and in machine language, where there are no branching constructs other than conditional or unconditional jumps (i.e. "goto").
No. See https://en.wikipedia.org/wiki/Goto#Common_usage_patterns It's still used in systems programming contexts and in machine language, where there are no branching constructs other than conditional or unconditional jumps (i.e. "goto").
> systems programming contexts
What does this mean?
> machine language
We're talking about C.
What does this mean?
> machine language
We're talking about C.
> > systems programming contexts
> What does this mean?
It means operating systems and similar places.
> What does this mean?
It means operating systems and similar places.
I feel like if goto is bad design it should be specially avoided in operating systems since they are so crucial to everything a computer does if it’s good design then why not adopt them in applications?
[deleted]
(I _like_ using goto's every once in a while: it can often mess up the gcc optimizer just enough to get better code out of it. In this case, as the signal test is not usually true, the goto forces gcc to use better jump placement and avoid the branch in the usual case).
As to whether it reall matters: no, it doesn't. The largest reason I do this once in a while is that I look at the assembly gcc produces for quite other reasons, and use a goto to make it slightly easier to read (not the C code, the assembly ;-)
http://lkml.iu.edu/hypermail/linux/kernel/9507/0475.htmlPlease note that this is from 1995. Compiler behaviour might have changed.
Other interesting posts:
https://marc.info/?l=linux-kernel&m=104240115806388&w=2
https://marc.info/?l=linux-kernel&m=104240357108566&w=2
https://marc.info/?l=linux-kernel&m=104240441009296&w=2
There's a one-page version of the latter conversation: https://koblents.com/Ches/Links/20-Using-Goto-in-Linux-Kerne...
C is sometimes called "portable assembly" because it allows you to use all of the features of a CPU's ISA (but it abstracts over the differences in opcodes). This includes GOTO, which is analogous to "JMP", which is the cornerstone of digital computing. In other words, FOR and WHILE are compiled to GOTO by your compiler anyway.
The idea that using GOTO is an indication of bad design was started by Edsger Dijkstra, and I've always found it to be a black spot on his reputation. Read it for yourself, and I think you'll come to the conclusion that he has no idea what he's talking about: https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.p... He has certainly no idea in what cases GOTO might be useful, and likely has never talked to anyone who was writing an OS kernel or driver. Remember, he was primarily an algorithms researcher turned educator, so his experience of the "Go To Statement" is entirely from students turning in programs for him to grade.
The idea that using GOTO is an indication of bad design was started by Edsger Dijkstra, and I've always found it to be a black spot on his reputation. Read it for yourself, and I think you'll come to the conclusion that he has no idea what he's talking about: https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.p... He has certainly no idea in what cases GOTO might be useful, and likely has never talked to anyone who was writing an OS kernel or driver. Remember, he was primarily an algorithms researcher turned educator, so his experience of the "Go To Statement" is entirely from students turning in programs for him to grade.
> and likely has never talked to anyone who was writing an OS kernel or driver
https://en.wikipedia.org/wiki/THE_multiprogramming_system
I think you have to appreciate Dijkstra's comment on goto by the standards of the era he said it. FORTRAN/COBOL/assembly spaghetti code was the norm then. At the time, software problems were scaling extremely quickly. He (and many others) felt that managing complexity was the issue for future development. Modularity and code reuse were barely known. (FORTRAN at the time had an infamous "if less than goto 1, if equal goto 2, if greater goto 3" control flow construct -- and no other conditional control flow!)
The UNIX inventors cited Dijkstra's views on structured programming as crucial to the development of a large system like UNIX... even though they did add goto to C :)
https://en.wikipedia.org/wiki/THE_multiprogramming_system
I think you have to appreciate Dijkstra's comment on goto by the standards of the era he said it. FORTRAN/COBOL/assembly spaghetti code was the norm then. At the time, software problems were scaling extremely quickly. He (and many others) felt that managing complexity was the issue for future development. Modularity and code reuse were barely known. (FORTRAN at the time had an infamous "if less than goto 1, if equal goto 2, if greater goto 3" control flow construct -- and no other conditional control flow!)
The UNIX inventors cited Dijkstra's views on structured programming as crucial to the development of a large system like UNIX... even though they did add goto to C :)
That's a fine use of goto and not in any way bad design in my opinion.
It makes it very clear that it's _REQUIRED_ to run the cleanup stuff regardless of the skipped block.
It does so without wrapping the entire skipped block in an IF (which also has two side effects: of causing more indentation and making the cleanup stuf look less required, or incidental).
It does so without adding another tiny silly, only-_REALLY_-used-on-place function for cleaning up, which decreases readability and causes more code duplication since there is then a need for not one, but two function calls and/or multiple return paths where not needed.
It makes it very clear that it's _REQUIRED_ to run the cleanup stuff regardless of the skipped block.
It does so without wrapping the entire skipped block in an IF (which also has two side effects: of causing more indentation and making the cleanup stuf look less required, or incidental).
It does so without adding another tiny silly, only-_REALLY_-used-on-place function for cleaning up, which decreases readability and causes more code duplication since there is then a need for not one, but two function calls and/or multiple return paths where not needed.
Many people tend to assume goto is bad design, and while it definitely can be, there are some great uses for it especially on low level code.
I feel like this idea of goto being bad dates back to Djikstra's essay about the subject. I think quite often people tend to reference this and based on that declare that goto is always bad while missing the point that Djikstra was actually talking about goto being harmful when proving algorithms, not necessarily in real world code where there are great use cases for it when used in moderation.
I feel like this idea of goto being bad dates back to Djikstra's essay about the subject. I think quite often people tend to reference this and based on that declare that goto is always bad while missing the point that Djikstra was actually talking about goto being harmful when proving algorithms, not necessarily in real world code where there are great use cases for it when used in moderation.
Even if it were suboptimal in that usage (but it looks like the best choice to me), the extent of the harm would be contained to the function body. Nothing outside could “see” that a goto was used.
If you worsened the function, such as by duplicating the cleanup code and using a return statement, that would be worse, and unacceptable, but still, the harm would be contained to the function body.
If you worsened the function, such as by duplicating the cleanup code and using a return statement, that would be worse, and unacceptable, but still, the harm would be contained to the function body.
This is the C equivalent of a try {...} finally {...} block and the Linux coding style allows it because it makes code cleaner.
some of possible reasons to use goto:
1. escape nested loops easily
some languages like Zig for example have keyword defer, this to my understanding implements an alternative to this approach
1. escape nested loops easily
for ()
...
for()
...
if (something)
goto get_me_out
...
get_me_out:
2. error handling; since c does it in somehow messy way, you can end up with multiple variations of: if (error)
close
return
if (error)
deallocate;
close;
return
where by using goto you can put those handlers as in a footnote of a function like if (error)
goto error1
if (error)
goto error2
error2:
deallocate
error1
close
as it looks a bit neatersome languages like Zig for example have keyword defer, this to my understanding implements an alternative to this approach
Note, however, that if you have multiple different cleanup-and-exit points, it can be a maintenance issue. (On the other hand, the non-goto version can also be a maintenance issue...)
Short Answer:
GOTO is used in very confined and careful manner. So, the statement that says "GOTO shall not be used" is only for the junior developers or newbies. Once someone gain experience, and knows what is going on, GOTO is safe to use.
GOTO is used in very confined and careful manner. So, the statement that says "GOTO shall not be used" is only for the junior developers or newbies. Once someone gain experience, and knows what is going on, GOTO is safe to use.
Linux uses goto statements to transfer control to another place in a function.
In a better language there would be little or no use for them, but Linux is still uniformly C.
In a better language there would be little or no use for them, but Linux is still uniformly C.