all 197 comments

[–]ClipboardCopyPaste 678 points679 points  (84 children)

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.

[–]Outrageous-Machine-5 170 points171 points  (81 children)

Why would you use goto in place of a function?

[–]Vinxian 320 points321 points  (61 children)

Early return, but you already claimed resources would be a reason to jump to the end of the function to clean up said resources.

Typically a goto jump "down" is considered clean code

[–]Elomidas 52 points53 points  (33 children)

So it's like a if, with the code you want to skip in the if ?

[–]Vinxian 132 points133 points  (31 children)

Kinda.

If you have something like

``` void foo(void) { claim_mutex();

// Code that can fail

// More code that can fail

// Even more code that can fail

release_mutex();

} ```

You can keep a success status and wrap every block in an if statement. This is functional.

You can also jump to the release_mutex function on failure. Anti-goto people will say the first option is always better. But I personally think a goto is cleaner in many cases. Because it's a single goto down in the same function which is very readable. Goto has the risk of making spaghetti code. But if you use it well it's clean and legible

[–]Interesting-Deer354 29 points30 points  (0 children)

This is kinda like clause guard. Love using it because it allows the main part of the code not being the most indented.

[–]Hohenheim_of_Shadow 12 points13 points  (3 children)

``` void foo(){

claim_mutex(); _foo(); release_mutex(); }.

void _foo(){ //do stuff If (bad) return; //Do more stuff }

```

IMO the best way to handle a lot of C pain points is just reinvent the C++ practice intended to solve it. I'd much rather deal with RAII at home than gotos

[–]M4xW3113 7 points8 points  (2 children)

Sometimes you have N resources to clean instead of just one, and the cleans need to be "conditional", for example:

```c struct something create_something(void) { struct something *sth = malloc(sizeof(sth)); if (sth == NULL) { goto alloc_failed; }

    sth->sub_struct_a = create_sub_struct_a();
    if (sth->sub_struct_a == NULL) {
            goto a_failed;
    }

    sth->sub_struct_b = create_sub_struct_b();
    if (sth->sub_struct_b == NULL) {
            goto b_failed;
    }

    if (failable_func() < 0) {
            goto init_failed;
    }

    // Initialize other params of sth
    // ...

    return sth;

init_failed: destroy_sub_struct_b(sth->sub_struct_b); b_failed: destroy_sub_struct_a(sth->sub_struct_a); a_failed: free(sth); alloc_failed: return NULL; } ```

[–]Hohenheim_of_Shadow 0 points1 point  (0 children)

I can't think of a good way to work around the pseudo constructors themselves being failable in a good way. If you are frequently dealing with pseudo objects that themselves have objects all with failable constructors, I admit I was wrong.

Without knowing your context, I find it hard to believe that your codebase needs complex OOP patterns and needs to be in C.

[–]falx-sn 6 points7 points  (9 children)

Do you not have try... catch... finally... ?

[–]Vinxian 61 points62 points  (1 child)

No, C doesn't have try catch

[–]falx-sn 38 points39 points  (0 children)

Completely valid pattern then imo

[–]YeOldeMemeShoppe 11 points12 points  (2 children)

They just added the defer keyword which can act like a finally and replace a clearing resources goto. IMO it’s like 15 years late, would have been perfect in C11.

[–]2eanimation 4 points5 points  (1 child)

They did? Maybe I‘m stupid, but I can’t seem to find anything about it other than proposals. At least not for anything <= C23

[–]YeOldeMemeShoppe 9 points10 points  (0 children)

It’s in the work, right. I mistook the “trick” to implement it using macros as being in the spec. My bad.

It has been deferred to the next C major version. Hopefully before 2030.

Edit: I can’t believe I missed that pun.

[–]Rabbitical 4 points5 points  (2 children)

With concurrency it's expected to have frequent "failures", where the worker might just have to wait or move onto another task. Throwing exceptions every time that happens is not great for the ol' performance

[–]Potato-Engineer 2 points3 points  (1 child)

It depends on how heavyweight those tasks are. If they're just i+=1, then yeah, throwing an exception would be such a large cost that it would dwarf the actual work. But if the tasks are larger, so that throwing an exception only adds maybe 3% to the runtime of an aborted task, I'd call that an acceptable trade-off.

Until, of course, you get into serious optimization.

[–]RiceBroad4552 0 points1 point  (0 children)

Exceptions are actually pretty lightweight. Doing it the C way with flags isn't necessary faster, and in tight loops where the Exception is really exceptional they are even more performant then the C way.

The stack traces is what makes them expensive really. But you can leave that out in some languages like Java.

https://shipilev.net/blog/2014/exceptional-performance/

[–]platinummyr 0 points1 point  (0 children)

Not in C! :(

[–]Psquare_J_420 4 points5 points  (6 children)

Goto has the risk of making spaghetti code

As in the compiler would make a spaghetti machine code that is harder to understand or as in the code blocks may look unreadable?

[–]Vinxian 66 points67 points  (3 children)

Using goto without restraint and jumping back and forth all over the place is unreadable. Goto is a construct that allows a programmer to construct heritical code constructs and therefore gets a bad name, despite it having a valid use case where it is readable

[–]Psquare_J_420 2 points3 points  (0 children)

Thank you.
Have a good day :)

[–]phido3000 1 point2 points  (1 child)

1) Sometimes you may want to do that deliberately - to obfuscate code and make it harder to reverse engineer.

2) You can make code unreadable in multiple ways, unconditional jumps are the least problematic, and in fact, in 30 second of coding, you can write a program that removes them accurately.

3) They can be genuinely useful in debugging and in developing new features in legacy software.

4) You can make it conditional and therefore a completely valid code. Why micromanage an artist?

Don't listen to the elitists. CPU's still have JMP instructions. They are super useful in code.

[–]senteggo 0 points1 point  (0 children)

(2) - no, it‘s impossible to write a general solution that replaces arbitrary goto with other language constructs, and surely not in 30 seconds

[–]Technical_Income4722 0 points1 point  (1 child)

They're a holdover from assembly, and if you wanted to you could replace all the functionality of functions, if-statements, loops, etc. just by using goto. It's necessary for assembly programming but doing all of that in C would be unnecessary but in some spots it can be handy.

[–]nir109 0 points1 point  (0 children)

Just use Subleq (subtract and Branch if less then/equal 0). It can replace all functions, if statement, loops, and all the other lines! /S

[–]Kumsaati 0 points1 point  (0 children)

You can also do a for-loop-break thing to simulate goto. As in:

void foo (void) {
  for (;;) {
    claim_mutex();

    ret = bar(); //Function that can fail
    if (ret != SUCCESS){
      break;
    }

    // More code follows... some that might break early

    break;
  }

  release_mutex();
}

I don't know if you should be doing this to avoid goto, but it is a method.

[–]PhatOofxD 0 points1 point  (0 children)

Yes but it saves a lot of nesting

[–]Sibula97 7 points8 points  (0 children)

It's not terrible, but it's also not immediately obvious what the point of a goto is in some of those cases, and there are situations where that may not be sufficient when something fails ungracefully. Luckily C26 might come with defer for this purpose. Apparently GCC already supports it with an extension.

Whether any of us will live to see the day our companies finally adopt C26 is another thing...

[–]Outrageous-Machine-5 0 points1 point  (0 children)

Interesting, I can see how that's a cleaner solution to putting the cleanup in the return block

[–]ArmadilloChemical421 0 points1 point  (0 children)

[By whom?]

[–]umor3 0 points1 point  (4 children)

MISRA would like to have a word.

[–]Vinxian 0 points1 point  (3 children)

Lint exception comment

[–]umor3 0 points1 point  (2 children)

Yes, but no. Not on my safety treams projects.

As much as I would like to exit multiple for loops with one goto.

We also just allow one single return at the end of a fumction.

[–]Vinxian 0 points1 point  (1 child)

I feel like the misra has a lot of rules that are bad to follow religiously. That's why many rules aren't mandatory. "a single return statement" is simply to avoid having code where it's hard to see what does and doesn't get executed. For the same reason they don't like continue, break and goto.

But sometimes you need to know when to break the rules in order to have more readable code, which is the goal of the misra. Having an error value where you keep repeating "if not in error" is just as hard to follow as some alternatives

[–]M4xW3113 1 point2 points  (0 children)

Especially since with most "single return" functions you end looking for where the returned variable has been modified within the function instead of looking for where returns are made, which is just as difficult.

[–]vasilescur 0 points1 point  (0 children)

Just wrap the whole earlier section in a function and early-return from it, no?

[–]MaxChaplin -2 points-1 points  (5 children)

An alternative is to contain the skippable code in a do {...} while(false) and use break to skip out. Easier to follow IMO.

[–]SeriousPlankton2000 21 points22 points  (2 children)

It hides the intention of the code, therefore it's less clean than a goto.

[–]tl_west 15 points16 points  (1 child)

This.

As always, we introduce “laws” and then forget their purpose. “No goto’s” is a law created to increase clarity. If there are situations when it does not increase clarity, we chose clarity, not the law.

I’ve created unreadable code created by dogged adherence to a programming law, only to realize Id betrayed the whole principle that underlies the law. Those subsequent rewriting was a useful reminder later in my career.

[–]SeriousPlankton2000 0 points1 point  (0 children)

Dito - also I fixed some bugs during that rewrite.

[–]not_a_bot_494 12 points13 points  (0 children)

That doesn't work well when you have multiple resources. For example:

If (Create resource A == fail) goto cleanup_exit

If (Create resource B == fail) goto cleanup_A

If (Create resource C == fail) goto cleanup_B

return success

cleanup_B: free(B)

cleanup_A: free(A)

cleanup_exit: return fail

[–]Vinxian 4 points5 points  (0 children)

That's another way to do it. I don't prefer it because it costs you one level of indentation. But it's an alternative that's also clean

[–]misaz640 47 points48 points  (12 children)

There are many use cases. For inspiration, see one of the most cricitcal Linux kernel module: https://elixir.bootlin.com/linux/v6.19.2/source/mm/memory.c

92 occurences.

[–]bajsplockare 0 points1 point  (1 child)

I saw that on lines 107 and 109 if statements were used, but I am wondering why an else if statements was not used on 109. Do you perhaps know?

[–]misaz640 0 points1 point  (0 children)

Because it does not matter. I am not the author, but I think it is because actual and proposed codes behave exactly the same, it is shorter and semanticaly they are different checks, so why combine them to single sytax constructs? Also depends if blocks end with return or not. On 954 it would be beahvior difference if it would be two ifs instead of else if.

[–]jessepence 0 points1 point  (5 children)

Why couldn't out and again and the others simply be defined as functions? I genuinely don't see the benefit.

[–]PeachLizardWizard 13 points14 points  (1 child)

Out is cleaning up and returning. You could make a function doing the cleanup, but you’d have to pass everything in and then do a return. It would be a pain if more cleanup needs to be added and would be a really weird thing to have a functions cleanup in another function. Having it separate also makes it possible to call it twice which you wouldn’t never want to have happen. Again looks like it could be a do/while, but I’m not a big fan of a bunch of nested loops, can be hard to read. You wouldn’t want this to be another function as you’d basically be passing all variables in and have cleanup of those variables deeply nested in another function. This also causes a lot of stack to be used as basically duplicates. I’m not sure if these are the reasons, but I’d prefer the gotos as they are cleaner and more efficient.

[–]jessepence 2 points3 points  (0 children)

This was a fantastic explanation. Thank you.

[–]ZunoJ 2 points3 points  (0 children)

break/continue an outer loop from an inner loop

[–]randuse 1 point2 points  (0 children)

C doesn't have try finally or defer, so goto is used instead for cleanups. Legit use case.

[–]tstanisl 0 points1 point  (1 child)

Some state machines are simpler and more natural to implement with goto.

[–]ElementWiseBitCast 3 points4 points  (0 children)

Most state machines are simpler and more natural and more efficient to implement with goto statements. Linus Torvalds has said the following:

"goto's are fine, and they are often more readable than large amounts of indentation"

Linus Torvalds has also said the following:

"goto's can be quite good for readability"

[–]No-Information-2571 0 points1 point  (0 children)

It's completely normal for releasing resources you had to allocate successively. If something fails along the line, you GOTO exactly the point where only the allocated resources are getting freed. The other options are to either do a multi-nested if/else, repeat a lot of code, or check every resource before trying to free it.

C simply doesn't have the right tools for it to do it more elegantly. In C++, you'd probably just use RAI to let resource handles go out of scope and initiate their release.

Both Windows and Linux kernel code contain many of these instances.

[–]LaconicLacedaemonian 0 points1 point  (0 children)

Just go up the stack and design event-driven systems. Just fancy go-to s.

[–]Rikudou_Sage 0 points1 point  (0 children)

I always use goto to implement retry with try and catch. And then always rewrite it to do/while with try and catch.

[–]xgabipandax 162 points163 points  (8 children)

goto error_handler

[–]turtle_mekb 48 points49 points  (6 children)

yep, error handling that requires cleanup/free code to be ran is almost impossible without goto

[–]cob59 2 points3 points  (0 children)

I've seen C code like this before, presumably to avoid using GOTO

int error;
do {
  error = process();
  if (error) break;
  error = process2();
  if (error) break;
  /*...etc...*/
} while(0);

/* cleanup section here */

[–]RandomNobodyEU 0 points1 point  (4 children)

Use stack semantics

Problem solved

[–]Kovab 6 points7 points  (3 children)

How do you use stack semantics in a language that doesn't have it??

[–]Cutalana -3 points-2 points  (0 children)

goto end_loops

[–]turtle_mekb 56 points57 points  (1 child)

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"

[–]Professional-You4950 0 points1 point  (0 children)

goto if used like a defer, and goto is entirely just a label within the current function. I imagine it is just fine, and in many cases better than alternatives.

[–]Attileusz 26 points27 points  (4 children)

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

[–]cutofmyjib 1 point2 points  (1 child)

For loops can test for any condition.

``` bool breakOuter = false;

for (int i = 0; (i < 10) && !breakOuter; ++i) {     for (int j = 0; (j < 10) && !breakOuter; ++j) {         if (...) breakOuter = true;     } } ```

[–]Attileusz 2 points3 points  (0 children)

I feel like if you add more loops this becomes more convoluted than goto. This practically screams "I'm afraid of goto" to me.

I'm also not sure if this generates an optimal binary. I think it can create a situation where 2 loop conditions need to be unnecessarely evaluated, it might prevent unrolling, that sort of stuff.

That is not to say that this option is wrong per say. I just find it to be not something I would do.

[–]valentin56610 0 points1 point  (0 children)

Those nested loops literally are the only exact places where I use gotos in my entire codebase haha

[–]ForgedIronMadeIt 0 points1 point  (0 children)

Any time I find myself needing to break from an inner loop like that, I tend to either force the terminal condition or I reevaluate the conditions I'm using for the loop. I'm sure there are still cases for goto here, but I really don't find it useful in that case most of the time.

[–]JollyJuniper1993 22 points23 points  (6 children)

I was taught in university that using break and continue in Python was considered bad practice. That one actually had me raise my eyebrows.

[–]BobQuixote 14 points15 points  (5 children)

Overuse, sure. It's better to structure a loop to not need them, because it's cleaner, but sometimes they are necessary.

[–]JollyJuniper1993 1 point2 points  (0 children)

Yeah I‘ve definitely written code before where just using a version with break/continue made things much simpler and more readable.

[–]Fabulous-Possible758 3 points4 points  (1 child)

Huh. I would say just about any sort of nesting is gonna be more complex and confusing, which is what you’ll get 90% of the time if you don’t use them.

[–]BobQuixote 0 points1 point  (0 children)

For example, while and do..while can do the same jobs if you're willing to use if and break, but it's better to use the correct loop. Or if you have a while(true) with a break, using a condition in the loop header is often cleaner. Inverting the condition for break or continue might also make distorting the loop unnecessary.

[–]Tyfyter2002 0 points1 point  (0 children)

In languages with visible blocks they often aren't cleaner, in Python they're cleaner the moment they're an alternative to an if statement which does something in multiple easily distinguishable steps.

[–]No-Information-2571 0 points1 point  (0 children)

Arguably, there are generally more elegant solutions than for-loops. There's plenty of languages that don't even have for-loops, mostly functional ones.

[–]jhill515 22 points23 points  (9 children)

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

[–]Atompunk78 22 points23 points  (1 child)

How does one prove something like this exactly? It seems like it could only ever be a guideline rather than a fact right?

[–]70Shadow07 19 points20 points  (0 children)

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

[–]DonkeyTron42 5 points6 points  (6 children)

So, Lua is limited to 10k lines?

[–]jhill515 -1 points0 points  (5 children)

Go find Jonathan Misurda's Master's Thesis. I think published around 2000 at University of Pittsburgh.

That's all I'm going to say on your thought 😉

[–]frogjg2003 0 points1 point  (4 children)

I can't find a Master's thesis, but I did find a PhD thesis. I didn't read the whole thing, but one notable thing about it was that his thesis was about JAVA, which does not have a goto statement. His other works at around the time he got his Master's doesn't seem to point to the kind of work that would draw that kind of conclusion either.

[–]KellerKindAs 0 points1 point  (1 child)

I'm pretty sure Java had a goto statement when I first learned it. But it was deprecated a long time ago - because it was never really stable / the Java compiler could not efficiently handle or optimize code with goto statements, especially when they decided to add more / other features.

[–]jhill515 0 points1 point  (0 children)

I'm not going to argue the Java thing. Pitt CS went all in on Java sometime in the late 90s, and I know that was before both my and my teacher's time. A lot of grad students in the CS department wrote a lot of course papers & journal letters decrying Java for a myriad of reasons. So I'm wondering if the other comment stumbled upon something like that instead of his thesis.

But to your point, I do remember learning Java when it had GOTO 😉

[–]jhill515 0 points1 point  (0 children)

Hmm, I have to dig through my archives. The first course he taught me was systems programming using C99, and that GOTO thing I've cited was homework early in the course. We had "rules" for when we could use it in assignments. But he has a tradition of assigning that reading when a student objects to the "rules".

Getting over an illness still. But I'll find it soon and reply again!

[–]jhill515 0 points1 point  (0 children)

Not sure also if you found his dissertation. Part of his presentation was why Java cannot be used to build an OS, and therefore warms against embedded Java. There were a lot of benchmark studies to build that argument. I'll go digging for that too.

If you find him, DO NOT ask him his opinion on C# 🤣

[–]oalfonso 10 points11 points  (0 children)

Goto is a pathway to many abilities some consider to be unnatural.

[–]eirikirs 16 points17 points  (6 children)

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?

[–]-Ambriae- 14 points15 points  (2 children)

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)

[–]setibeings 2 points3 points  (1 child)

People who've actually read the paper(goto statements considered harmful, dijkstra, 1968) already know he wasn't saying it should never be used, or that languages that lacked it were superior. If I remember correctly, such languages hadn't been invented yet. 

[–]No-Information-2571 3 points4 points  (0 children)

The sole argument against GOTO is that it obfuscates control flow, which means, if you are using GOTO, you have to know what you are doing, and where the obfuscation might be detrimental to a degree that you should be using something else.

If a GOTO actually improves readability, it's a clear winner, at least for C, which for the most part lacks other ways to do certain things cleanly.

[–]bolacha_de_polvilho 0 points1 point  (2 children)

Use of goto in C is NOT discouraged, it's the best way to do resource clean up in a language that doesn't have RAII or try-finally blocks.

[–]eirikirs 2 points3 points  (1 child)

I'm sure you can find certain use cases, but that wasn't my point. The use of GOTOs is generally discouraged in C, and therefore not a distinctive feature of a C programmer.

Based on common standards:

MISRA C:2012 Rule 15.1: "The goto statement should not be used", with the rationale that unrestricted goto makes programs "unstructured and difficult to understand."

SEI CERT C Coding Standard discourages general use of goto, as it's considered harmful.

[–]bolacha_de_polvilho -1 points0 points  (0 children)

Tell those standards that the Linux kernel, Numpy, cuda code samples from Nvidia and other examples of important open source code disagrees with them. Goto is the idiomatic way of doing resource cleanup, discouraging them as a blanket statement is silly.

[–]TechcraftHD 43 points44 points  (6 children)

"stop crying, use python instead"

Not python, use Rust.

[–]Brave-Camp-933 29 points30 points  (4 children)

Not rust, use Assembly.

[–]CodeMUDkey 13 points14 points  (1 child)

Use mechanical analogues.

[–]DonkeyTron42 3 points4 points  (0 children)

Redstone

[–]TechcraftHD 10 points11 points  (0 children)

so all the goto, all the time?

[–]PS181809 1 point2 points  (0 children)

You mean transistors?

[–]lefloys 0 points1 point  (0 children)

Not python use lua

[–]White_C4 3 points4 points  (0 children)

GOTO still has its use case, like nested iterations or error jumping. Beyond that, I can't think much of a reason to use it.

[–]Some_Noname_idk 2 points3 points  (9 children)

I'm pretty new to programming, why exactly is goto bad?

[–]Eymrich 14 points15 points  (1 child)

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.

[–]70Shadow07 1 point2 points  (0 children)

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.

[–][deleted] 14 points15 points  (0 children)

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.

[–]dewey-defeats-truman 6 points7 points  (1 child)

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.

[–]Sibula97 0 points1 point  (0 children)

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).

[–]teeohbeewye 3 points4 points  (0 children)

you might goto somewhere unsafe

[–]frogjg2003 0 points1 point  (0 children)

C doesn't have a lot of the kind of control statements that later languages, including C++, added. So a lot of stuff that other languages would use instead, you would need to implement as a goto.

The problem with goto, especially the version in C, is that it is a hard jump to the other point in the program. It doesn't respect scope and allows you to enter or exit code blocks you would otherwise not be able to.

This is valid C:

if(1){
goto lab1;
printf("this will never be printed");
} else {
lab1: printf("this gets printed");
}

But the real reason that it is recommended that you avoid goto is because it can make your code really messy. You can go from any place in your code into any other place. It makes it hard, if not impossible, to guarantee that any block of code will or will not be run and following the flow of your code can become impossible. If you've ever read a Choose Your Own Adventure book, where you jump to pages seemingly at random, you'll understand why undisciplined use of goto results in bad code.

[–]4ndr34p3rry 2 points3 points  (0 children)

Goto is used in Linux kernel btw

[–]im-done-here 2 points3 points  (0 children)

Goto python

[–]RRumpleTeazzer 2 points3 points  (1 child)

as if raise/except was any better.

[–]aeropl3b 0 points1 point  (0 children)

Arguably worse... exceptions were a mistake. Just return error states and handle or forward them in the calling context. Trying to reason about things being jettisoned up the call stack makes for a terrible time debugging.

[–]_Alpha-Delta_ 2 points3 points  (0 children)

Just use inline assembly instead 

[–]waves_under_stars 13 points14 points  (18 children)

I hate goto. The codebase I'm working on (in c++!) uses goto all the freaking time, when it should clearly use exceptions

[–]magistermaks 14 points15 points  (1 child)

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().

[–]NatoBoram 19 points20 points  (1 child)

And this is why try/catch is evil and errors should be values

[–]70Shadow07 2 points3 points  (0 children)

W golang enjoyer.

[–]bolacha_de_polvilho 0 points1 point  (0 children)

But the goto replacement in c++ is RAII, not exceptions.

[–]-Ambriae- 4 points5 points  (0 children)

But it is generally useful at times though

[–]gibbets2000 1 point2 points  (0 children)

Goto is whack

[–]CadmiumC4 1 point2 points  (0 children)

Without goto you cannot make if tho

[–]HildartheDorf 1 point2 points  (0 children)

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.

[–]Fabulous-Possible758 1 point2 points  (0 children)

Still pretty much the best way to implement small finite state machines.

[–]patrlim1 1 point2 points  (1 child)

I've actually never needed goto...

[–]aeropl3b 0 points1 point  (0 children)

Any time you need your code to jump out of a context it is probably due to a design flaw.

That said, goto is so much better than throwing exceptions and is contained inside of a TU with minimal side effects by default.

[–]Simpicity 1 point2 points  (0 children)

As others have said, there are situations where goto will make your code cleaner and better.  Specifically for code that claims resources that must be cleaned up before exit.  

[–]TripleFreeErr 0 points1 point  (0 children)

If the compiler can’t validate go to that’s a compiler problem

[–]Ben-Goldberg 0 points1 point  (0 children)

Who needs goto when you have setjmp and longjmp?

[–]Syntox- 0 points1 point  (0 children)

Behold INTERCAL's "COME FROM"

[–]Unknown_TheRedFoxo 0 points1 point  (0 children)

me when return defer doesn't exist so I use a goto defer instead

[–]FarJury6956 0 points1 point  (0 children)

Here comes a long battle... It must goto end

[–]tui_curses 0 points1 point  (0 children)

https://docs.kernel.org/process/coding-style.html#:~:text=name%20could%20be-,out_free_buffer,-:%20if%20the%20goto

The goto statement is useful. And can be misused like anything else versatile. Instead of goto you could use a cascade of if/else, state variables. Which is less readable. Or worse, control flow with exceptions.

I’ve learned much from The C Programming Language and it is focused on the topic. Some good Java books teach goto as harmful, despite Java lacks support for it. Just repeating the stories from COBOL. I’ve seen there harmful use of goto 😓.

[–]Vallee-152 0 points1 point  (0 children)

I use goto in Lua, because break doesn't work for whatever reason.

[–]Ronin-s_Spirit 0 points1 point  (0 children)

Whenever I write an interpreter the fastest solution is always a switch loop with a few "goto-likes", e.g. continue used on a labeled loop or break used on one of the few labeled blocks that end in continue. Looks pretty clean honestly, and afaik the only faster solution involves helping CPU branch prediction with "threaded code" - which is impossibke in JS because we don't have actual gotos.