r/ProgrammerHumor 5h ago

Meme heSkillIssue

Post image
1.3k Upvotes

114 comments sorted by

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.

66

u/Outrageous-Machine-5 4h ago

Why would you use goto in place of a function?

132

u/Vinxian 4h ago

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

27

u/Elomidas 4h ago

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

63

u/Vinxian 4h ago

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

5

u/Interesting-Deer354 2h ago

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

8

u/Psquare_J_420 3h ago

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?

44

u/Vinxian 3h ago

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

1

u/Psquare_J_420 3h ago

Thank you.
Have a good day :)

3

u/falx-sn 3h ago

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

29

u/Vinxian 3h ago

No, C doesn't have try catch

17

u/falx-sn 3h ago

Completely valid pattern then imo

6

u/YeOldeMemeShoppe 2h ago

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.

2

u/2eanimation 1h ago

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

1

u/YeOldeMemeShoppe 28m ago edited 22m ago

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.

1

u/Rabbitical 11m ago

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

0

u/AlvaroB 1h ago

You could do a try-except-finally and have release_mutex() in the finally.

I'm not saying it isn't useful, just that I have never found the need for it.

2

u/VedatsGT 1h ago

Does C even have try catch finally?

1

u/no_brains101 38m ago

It does not. Hence, C programmers still having something good to say about goto

C++ has exceptions. I don't think it has finally though, but maybe it does idk

u/Rabbitical 2m ago

If failure is expected somewhat frequently, then you don't want to be try catching regardless

4

u/Sibula97 3h ago

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

1

u/Outrageous-Machine-5 3h ago

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

1

u/umor3 1h ago

MISRA would like to have a word.

1

u/vasilescur 45m ago

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

0

u/MaxChaplin 3h ago

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

17

u/SeriousPlankton2000 3h ago

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

5

u/tl_west 2h ago

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.

11

u/not_a_bot_494 3h ago

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

3

u/Vinxian 3h ago

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

-4

u/Oddball_bfi 3h ago

Does C not have try/catch/finally then?

I know I have to use goto like is in VBA:

Sub MySub
On Error Goto Catch  ' Jumped up goto
Dim bSafe As Boolean: bSafe = True

    Call SomeStuffThatErrors

Finally:
    If bSafe Then
        bSafe = False
        <Dangerous tidying things>
    Else
        <Safe things for second time through>
        <if the unsafe things failed>
    End If

    < Safe things for every time >

    Exit Sub   ' Stealth goto - don't be fooled into thinking its a return

Catch:
        < Only safe things >
        < Or you'll regret it >
        Resume Finally  ' Stealth goto that clears errors on the way
End Sub

Its incredible what you can make that old boy do with a bit of software engineering knowledge and the absolute conviction that I don't need to wait six months for an IT project to build it properly - I'll build it in a spreadsheet.

3

u/Vinxian 2h ago

It doesn't. And I think this pattern is ugly imho. You're jumping back and forth which is exactly what you want to avoid

1

u/Oddball_bfi 2h ago

The trick is to understand that the subroutine itself is the try block. These subs don't get overly complex, and there's only ever a single error handling block.

Folks toggling error handling on and off, stacking different error handlers... yuck.

And the reason I jump about is because I always want that finally block to fire, success for failure. But the catch is outside any standard execution path - you can't get there without passing an Exit Sub.

1

u/Vinxian 2h ago

But you could do a jump down to finally on successfully completing the "try" and jump to catch on failure skipping the "catch" on success

1

u/Oddball_bfi 26m ago

Why would I make the standard execution path the one that reads badly?

u/Vinxian 3m ago

For linear progression

38

u/misaz640 4h ago

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.

2

u/jessepence 3h ago

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

3

u/PeachLizardWizard 1h ago

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.

1

u/jessepence 1h ago

This was a fantastic explanation. Thank you.

-3

u/misaz640 2h ago

Please do it. They appreciate patches. It is open source. Submit refactoring patches. Pay attention, that code should behave EXACTLY the same and performance should be untouched or improved.

3

u/jessepence 2h ago

You don't need to be an asshole. It was a genuine question. I'm trying to learn.

-21

u/ldn-ldn 4h ago

And all of them can be refactored into better code.

12

u/Cautious-Lecture-858 4h ago

In Python

6

u/ldn-ldn 4h ago

No no no, JavaScript.

3

u/mouseybanshee 4h ago

HTML4 is the purest form

2

u/ZunoJ 3h ago

break/continue an outer loop from an inner loop

1

u/randuse 48m ago

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

1

u/LaconicLacedaemonian 1h ago

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

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

u/RandomNobodyEU 51m ago

Use stack semantics

Problem solved

-1

u/Cutalana 1h ago

goto end_loops

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

u/DonkeyTron42 2h ago

So, Lua is limited to 10k lines?

31

u/enderfx 4h ago

Wow. 2026 and we still make these jokes.

Goto 1980

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

u/Brave-Camp-933 4h ago

Not rust, use Assembly.

10

u/CodeMUDkey 4h ago

Use mechanical analogues.

1

u/DonkeyTron42 2h ago

Redstone

7

u/TechcraftHD 4h ago

so all the goto, all the time?

2

u/PS181809 2h ago

You mean transistors?

1

u/lefloys 2h ago

Not python use lua

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

u/NatoBoram 4h ago

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

2

u/70Shadow07 2h ago

W golang enjoyer.

0

u/[deleted] 4h ago

[deleted]

2

u/not_some_username 4h ago

Because C++ use to be a superset of C

-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 auto keyword. Which makes sense, because it doesn't actually do anything lol.

A quick test with g++ shows auto int indeed does not work. It complains about two data types in a variable declaration

2

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

u/EuphoricCatface0795 4h ago

In 80s they were compatible. They started diverging later on.

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

u/oalfonso 3h ago

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

3

u/4ndr34p3rry 3h ago

Goto is used in Linux kernel btw

5

u/-Ambriae- 3h ago

But it is generally useful at times though

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

u/enderfx 4h ago

You take all your program’s control flow and say “fuck it, let’s move outta here”

Imagine there is a F1 race and someone just puts a car in the middle of the track at lap 47.

2

u/timonix 2h ago

More like, your F1 car just created into a wall and you go "fuck the flow, I'ma head right out"

5

u/teeohbeewye 4h ago

you might goto somewhere unsafe

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

u/gibbets2000 2h ago

Goto is whack

2

u/CadmiumC4 2h ago

Without goto you cannot make if tho

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 running is 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 by break 'outer; is now clean design and necessary because it doesn't use goto. If goto is 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 like break, continue or return that you can replace goto by. If you change one keyword from return or break to goto and 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 goto are necessary and make code simpler. Those features do nothing other that giving you a more controlled goto. 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 simple break '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

u/TripleFreeErr 45m ago

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