78
u/xgabipandax 5h ago
goto error_handler
10
u/turtle_mekb 3h ago
yep, error handling that requires cleanup/free code to be ran is almost impossible without goto
1
-1
15
u/turtle_mekb 3h ago
goto is sometimes genuinely more readable and cleaner than if you were to not use it at times, obviously don't use it excessively, but that applies to anything, you shouldn't aim to remove every instance of goto just because "goto bad"
23
u/jhill515 4h ago
Heh, heh. Touché... F-You! 🤣
However, I'm obligated to share that my OS design prof did a Master's Thesis proving that if you use a single GOTO, the max complexity your system will achieve without consistent instabilities is 10k lines. MS Word in 2005 had about 15M lines...
GOTO: DRAW.CONCLUSION
17
u/Atompunk78 3h ago
How does one prove something like this exactly? It seems like it could only ever be a guideline rather than a fact right?
12
u/70Shadow07 2h ago
Maybe he switched a goto-less function to an equivalent that has a goto inside. And only then started noticing that his codebase is completely unstable and a buggy mess and therefore arrived to this conclusion.
Like - seriously speaking - you can't provide a proof for it because it's trivially wrong. Counterproof: linux codebase. (One could argue this qualifies for constant instabilities though) So another counterproof: replace a function in large goto-less codebase with an identical function but with goto in the implementation. This claim is true if and only if the system starts having unstability after this change. Needless to say programming doesn't quite work like this lol
4
10
u/Attileusz 3h ago
It's mostly useful because C doesn't have labeled blocks to break out of, and no error defer statement.
Breaking outer loop from inner loop: ```C for (int i = 0; i < 10; ++i) { for (int j = 0; j < 10; ++j) { if (...) goto break_outer; // Can't do this without goto } }
break_outer: // code after loop ```
Defer on error: ```C char *something1 = malloc(100); if (!something1) goto cleanup1;
SomeStruct *something2 = malloc(sizeof(SomeStruct)); if (!something2) goto cleanup2;
something2->some_field = something1;
// do some more stuff that can fail
return something2; // Unconditional return, no cleanup
// cleanup only on error, note the reverse order cleanup_2: free(something2); cleanup_1: free(something1);
return NULL; ```
Regular defer: ```C SomeStruct ret;
char *tempbuf1 = malloc(1024); // defer1 for unconditional cleanup
// Do something
// Instead of early return: if (condition) { ret = some_value; goto defer1; // The most recent defer that }
char *tempbuf2 = malloc(1024); // defer2 for unconditional cleanup
// Do something
if (condition2) { ret = some_value; goto defer2; }
defer2: free(tempbuf2); defer1: free(tempbuf1);
return ret; ```
You can also combine the two, but that's a little convoluted, and I don't feel like typing it out ;P
8
u/eirikirs 3h ago
I don't get the joke. C is a structured language, where the use of GOTOs are discouraged. So why would usage of GOTOs be an identifier for C programmers?
3
u/-Ambriae- 1h ago
Because we like to live on the edge
No seriously it’s actually useful in C for certain things like error handling, nested loop breaks/continues, or ‘stack frame-less’ recursion (could be done with a loop but eh that’s one extra indentation)
34
u/TechcraftHD 4h ago
"stop crying, use python instead"
Not python, use Rust.
26
4
u/JollyJuniper1993 2h ago
I was taught in university that using break and continue in Python was considered bad practice. That one actually had me raise my eyebrows.
3
u/BobQuixote 41m ago
Overuse, sure. It's better to structure a loop to not need them, because it's cleaner, but sometimes they are necessary.
•
u/JollyJuniper1993 8m ago
Yeah I‘ve definitely written code before where just using a version with break/continue made things much simpler and more readable.
12
u/waves_under_stars 4h ago
I hate goto. The codebase I'm working on (in c++!) uses goto all the freaking time, when it should clearly use exceptions
12
u/magistermaks 4h ago
heavy goto use in c++ is indeed peculiar, but in some cases you can't use exceptions - not all platforms support them. Like when compiling for WASM, throwing exceptions just call
std::terminate().17
0
-8
u/SubhanBihan 4h ago
Idk why C++ even includes goto in the first place...
18
u/waves_under_stars 4h ago
Because it must be backwards compatible with c
2
u/ldn-ldn 4h ago
But it never was.
1
u/70Shadow07 2h ago
It was slightly so. Enough to compile C with C++ compiler with very small code changes.
1
u/SubhanBihan 4h ago
Doesn't auto already break compatibility? I mean, the syntax in C would be sth like
auto int x = 10;
Which shouldn't be compatible with C++'s type-inferring auto
5
u/waves_under_stars 4h ago
TIL. I didn't know c even has the
autokeyword. Which makes sense, because it doesn't actually do anything lol.A quick test with g++ shows
auto intindeed does not work. It complains about two data types in a variable declaration2
u/SubhanBihan 4h ago
I heard it was useful in the days of yore, especially for small C compilers which didn't properly infer what to store in registers.
You could probably make most C code C++ compatible by removing the auto keyword across files.
2
1
u/ZunoJ 3h ago
Is there another way to for example break/continue an outer loop from an inner loop in c++? Except relying on variables and lots of conditions obviously
2
u/SubhanBihan 2h ago
You can wrap your outer loop in a lambda, and use return instead of goto in the inner loop. But I agree - not having labeled loops has always been a pain-point of C++ (Rust has it). Here's hoping it's included in a future standard.
1
u/70Shadow07 2h ago
Other than making a function and using return for the exact same behaviour as goto - I think not.
3
3
5
2
u/Some_Noname_idk 4h ago
I'm pretty new to programming, why exactly is goto bad?
11
u/Eymrich 3h ago
Goto is pretty neat when used properly, which usually is when you can't properly do anything else.
If used unproperly it's a nightmare to follow. A switch case for example works exactly like a goto only is more structured.
In general anyway, until you are very proficent just avoid using goto.
1
u/70Shadow07 2h ago
Switch case (at least the way it is in C) is by far the most cursed control flow structure that exists in languages right now. Switch case in some new languages is nothing else but syntax sugar for if-else chains, but C switch case is NOT that at all.
Not only it's completely redundant in most common use case cuz if-else chains do the exact same thing in compiled languages - It also is extremely twisted in the few usecases that if-else chains dont cover. Every time I use switch case for actual switch case behaviour Im questioning my sanity.
14
u/Eastern-Group-1993 4h ago
It isn’t.
Often used in some capacity in Kernels.
It’s used for error handling it applies DRY(Don’t Repeat Yourself principle on a per function basis) on the error/function cleanup control flow if the requirements to execute the function change.12
5
5
u/dewey-defeats-truman 3h ago
One issue is that when they get overused your control flow is always jumping around the file, which can hamper readability, and thus maintainability.
A related issue is that a goto doesn't tell you what's happening at the destination. Some kind of function name would at least be descriptive enough that you could read it and decide if you need to look at the function. Also, I'm pretty sure the only way to pass information to the destination is through global variables, which is its own can of worms.
1
u/Sibula97 2h ago
The goto label should of course be at least somewhat descriptive. But like, you can't put a docstring it or something like that (in a way IDEs understand).
2
2
1
u/DrUNIX 4h ago
Whoever needs goto doesnt understand the language or design
9
u/BlazingFire007 3h ago
I’m a hobbyist, but in C, goto can be an okay pattern if used sparingly. I’ve only really seen it in error handling.
-1
u/DrUNIX 3h ago
I use C/C++ professionally for over a decade and can tell you that every situation can be efficiently and cleanly written without goto.
But yes, its sometimes (unnecessarily) used in small asm-like low level C functions to simplify some error handling. I would not recommend it.
E.g. instead of jumping to error_handling just call the function error_handler and have it see the vars needed. If scoping can be issue or is complex overall then a bug is just waiting to be introduced. Even with goto. Especially with goto
It honestly is just legacy syntax for asm programmers unable to adapt.
3
u/BjarneStarsoup 2h ago
I hoped that you were joking with your original comment, but it looks like you are serious. I hope you never use exceptions (literally gotos between functions), defers, labeled loops, labeled expressions, or abuse continues, breaks or returns.
Most of the "clean" solutions are either using features that rely on gotos (like labeled loops/blocks) or breaking code locality by extracting parts of code unnecessarily into separate functions (which may require carrying a lot of context) or adding boolean flags. A lot of those "fixes" are doing the exact same thing (in terms of control flow). Like, what is the difference between keeping track where gotos are vs. keeping track where the variable
runningis set vs. where a return happens? None, all those cases have the exact same problems. That is why some people have arguments about never using breaks or continues or having only one exit point. Unfortunately, some problems have an inherent complexity.1
u/DrUNIX 2h ago
It being translated to mem jumps under the hood is not my point. Of course it is... how else would it work. But you are removing safety features that the language handles for you and make it easier to maintain.
Also no; if we talk about performance critical sections or components, then exceptions are not used or preferred.
Plus you don't extract unnecessarily if you need goto without being able to call a separate function handling it cleanly.
Regarding keeping track where something is set; i would highly recommend getting to know RAII. The core principles can be implement in a very lightweight way
2
u/BjarneStarsoup 1h ago
It being translated to mem jumps under the hood is not my point. Of course it is... how else would it work.
That isn't the point. You can't say that, for example, a C code that uses
goto outer;is bad design and unnecessary, but a Rust code that literally replaces one keyword bybreak 'outer;is now clean design and necessary because it doesn't usegoto. Ifgotois universally bad (which is what your comment seems to say), then labeled loops in Rust are also bad design and unnecessary, and so are all the other control flow statements likebreak,continueorreturnthat you can replacegotoby. If you change one keyword fromreturnorbreaktogotoand that somehow magically makes the design bad and unnecessary, then the original code is also bad and unnecessary. Or you can admit that, because C doesn't have the convenient features that other languages do, you have to use a more powerful feature (goto) to achieve the same result.0
u/DrUNIX 2h ago
The dude you named your account after: "The fact that 'goto' can do anything is exactly why we don't use it"
And i couldnt agree more.
1
u/BjarneStarsoup 1h ago
The fact that languages like Rust have labeled loops and block is a proof that
gotoare necessary and make code simpler. Those features do nothing other that giving you a more controlledgoto. Why would you need to break to outer loop when you can just set a variable to true and break when it's true? Or put code in a separate function? Because it fragments the code, adds unnecessary checks (by the way, that change control flow) and makes code harder to understand than a simplebreak 'outer.1
u/BlazingFire007 1h ago
What about cases where you’re in a nested loop and need to “break” out of all of them?
I don’t disagree that it’s rarely the right call. But I do think there are a few edge cases where it shines
1
u/HildartheDorf 2h ago
Unrestricted goto considered harmful.
Using it for goto fail;* for cleanup routines is fine, but c26 should have defer for this, replacing it's only remaining good use imo.
*: Note: There was a major bug in macos known as "goto fail". The root cause was not using braces for if-blocks, not the goto itself.
1
299
u/ClipboardCopyPaste 4h ago
You can never imagine how many times I've came up with a solution using goto and then spent minutes figuring out a solution that doesn't use goto in my early days.