why is it illegal to use "goto"?

Sdílet
Vložit
  • čas přidán 16. 05. 2024
  • Should you use goto statements? What does a goto statement even do? Why are they bad? or... are they? In this video, we talk about what a goto statement is, when it's bad to use them and how to use them well in your code!
    🏫 COURSES 🏫 Learn to code in C at lowlevel.academy
    📰 NEWSLETTER 📰 Sign up for our newsletter at mailchi.mp/lowlevel/the-low-down
    🙌 SUPPORT THE CHANNEL 🙌 Become a Low Level Associate and support the channel at / lowlevellearning
    Why Do Header Files Exist? • why do header files ev...
    How Does Return Work? • do you know how "retur...
    🔥🔥🔥 SOCIALS 🔥🔥🔥
    Low Level Merch!: lowlevel.store/
    Follow me on Twitter: / lowleveltweets
    Follow me on Twitch: / lowlevellearning
    Join me on Discord!: / discord
  • Věda a technologie

Komentáře • 802

  • @LowLevelLearning
    @LowLevelLearning  Před 6 měsíci +39

    wanna get good at programming? check out lowlevel.academy and use code THREADS20 for 20% off lifetime access. or dont. im not a cop

    • @pepsitoly
      @pepsitoly Před 6 měsíci

      What standard of C do you use in this course? I hope it's ANSI c89. I really enjoy your videos, you are one of the persons that inspired me to learn C. And the project you've picked is just brilliant. I just wish to finish Herbert Schildt C++ Reference (only C part) and Dennis Ritchie C programming language books before starting your course, I hope it makes sense

    • @miboxtv_maison9193
      @miboxtv_maison9193 Před 6 měsíci

      There is an other way where using goto is more readable. Make break with multiple loop. Without goto, we have to define an exit variable, and the test statement of the loop looks unreadable.

  • @jimnoeth3040
    @jimnoeth3040 Před 6 měsíci +586

    I've been programming for over 50 years and goto has a definite place in the toolbox. Now for highly structured languages such as C/C++, Java, etc. goto can be somewhat confusing. But for procedural languages such as cobol (yes, cobol is still used today), Fortran, etc. goto can actually make the code more readable and, moreover, more efficient. For assembly language, goto is a necessity.

    • @elpatosilva
      @elpatosilva Před 6 měsíci

      Edsger Dijkstra probably hates you. Just like BASIC

    • @anon_y_mousse
      @anon_y_mousse Před 6 měsíci +41

      It annoys me when people group C and C++ together as though they're the same language. It was already easy to make a program that was valid in one but invalid in the other by C99, but now it's nearly impossible to not hit that wall. Java kind of pisses me off due to how little foresight they had in designing it. Not merely removing goto but making it a reserved keyword that generates an error at compile time, and then they had to add functionality to break and continue just to make up for the deficiency which caused a lot of problems that C++ already solved but in a more elegant way while still allowing you to use goto for those problems where it was still somewhat necessary. I guess what I'm driving at is that these ideological stances that people take based on inexperienced programmers misusing tools leads to garbage language design as well as garbage program design and I wish the lies that perpetuate them would stop cropping up. The old Knuth quote about premature optimization really irks me too.

    • @anon_y_mousse
      @anon_y_mousse Před 6 měsíci +5

      @@bb-sky But it *is* telling it to continue, from the top of the loop. Though, I wouldn't be opposed to using next as the keyword to start the next iteration of a for loop, it wouldn't make sense in the context of a while or do/while loop, and in the interest of lowering the keyword count I'd delete the one that's the odd man out.

    • @anon_y_mousse
      @anon_y_mousse Před 6 měsíci +1

      @@bb-sky Interesting perspective. But you'll have to come up with a better word than next or skip to convince me. I can't think of a word that's more apt than continue, only phrases.

    • @1sthaloman
      @1sthaloman Před 6 měsíci +2

      @@anon_y_mousse restart?

  • @ChunGzter
    @ChunGzter Před 6 měsíci +619

    You can also write a function that does this for you and call that function with different parameters if you are scared of the unstoppable errors that might come with this approach.

    • @talkysassis
      @talkysassis Před 6 měsíci +56

      This can lead to some ugly bugs by getting the file pointer on another scope

    • @GuentherJongeling-hu6oe
      @GuentherJongeling-hu6oe Před 6 měsíci +52

      Function calls add quite a bit of overhead compared to goto statements, unless they're inlined (which from my experience doesn't happen very often)

    • @lMINERl
      @lMINERl Před 6 měsíci +18

      ​@@talkysassisuse rust if you want to be safe and 0.001 ms wont make a difference, for some embedded systems you have limited size and memory.

    • @TheRobbix1206
      @TheRobbix1206 Před 6 měsíci +28

      Splitting the logic of the function with it's error path in another function tends to make things much messier and make easier bug as you need to sync the error with your function in any case.
      You also might pass a crazy amount of params of your function to your error function !

    • @jeffery_tang
      @jeffery_tang Před 6 měsíci +7

      but with a function you can't break, continue, or return from the function that it was called from

  • @ishi_nomi
    @ishi_nomi Před 6 měsíci +343

    Yeah agree. The error handling case mentioned here and sometimes breaking multi-layers of for loops is where goto make more sense than normal control flow. They are literally everywhere even in source code of linux kernel.

    • @georgerogers1166
      @georgerogers1166 Před 6 měsíci +21

      Or exiting a loop in a switch.

    • @nolanfaught6974
      @nolanfaught6974 Před 6 měsíci +20

      Their use is recommended in the kernel to support a “centralized control flow” method of coding

    • @monad_tcp
      @monad_tcp Před 6 měsíci +1

      Its because normal control flow is lacking in the C language. Something like "try/finally" , I don't know.

    • @jbird4478
      @jbird4478 Před 6 měsíci +18

      @@monad_tcp try/finally is not normal control flow but exception handling, which requires quite a lot of runtime support. C is just too low level for that. That's not to say you can't implement it in C, but it's not part of the standard language because that is designed to be portable across a huge amount of different systems. Try/finally requires stack unwinding, which is very system specific. With gcc, exception handling for C++ is actually implemented in C. Under the hood of course, all control flow eventually boils down to a form of 'goto'.

    • @monad_tcp
      @monad_tcp Před 6 měsíci +3

      @@jbird4478 try/catch/finally is control flow.
      It changes the point where the execution of code is going, therefore it is a control flow statement, compared with all the other nodes in the AST that are considered expressions, not statements.
      I'm using a formal definition here. (not the C programming language specification, but more general)
      You might correctly argue that C is low level for that sort of control flow, you might be right, C is a "mere" macro-assembler.
      On the other hand, even function calls might be considered special "control flow" as the C programming language does run in hardware without a stack.
      All of that is merely an implementation detail.
      But you do have a point.

  • @Trekiros
    @Trekiros Před 6 měsíci +52

    I've only had to use a goto once in ten years, to escape a highly-nested for loop. I could have "unrolled" the for loop and turned it into 5 functions, but I tried that, and it resulted in a code that was less readable than with a simple goto. My boss fought me for it, but in the end, dogmas and tradition matter less than producing code our teams can actually use and maintain easily.

    • @drachefly
      @drachefly Před 4 měsíci +5

      couldn't you have used a labeled break?

    • @xeridea
      @xeridea Před 4 měsíci +7

      @@dracheflydepends on the language, some languages support specifying now many loops to break, which is error prone, and/or some have labeled breaks, while others don't. I would say goto is essentially a labeled break, since this is the only real use I see in it in 99.9% of cases. It is still clean because the jump is directly after the loop to be broken, so you don't make spaghetti like this video made.

    • @amigalemming
      @amigalemming Před 22 dny +1

      @@drachefly or put the loop in an extra function and leave both the loop and the function with a 'return'.

    • @drachefly
      @drachefly Před 22 dny

      @@amigalemming That'd work too!

    • @simongido565
      @simongido565 Před 10 dny

      @@amigalemming Exactly what I had in mind.

  • @metal571
    @metal571 Před 6 měsíci +62

    In C, handling errors in resource acquire/release is already error prone, and goto specifically for this case and only for forward jumps reduces human error. This is a common pattern in kernel code itself. If you're using C++, you'd be doing it wrong by using goto since we've got Resource Acquisition Is Initialization there.

    • @IBelieveInCode
      @IBelieveInCode Před 6 měsíci

      Agreed.

    • @niewazneniewazne1890
      @niewazneniewazne1890 Před 6 měsíci +1

      The important part is once you're in a label you can't define new varriables within the label, which pretty much does limit the usefullness of gotos as a tool for error handling;
      The only other way I used gotos is for EINTR to avoid using:
      do { } while (ret (== || !=) -1);
      As it introduces the issue that you might forget to break out of the loop if you use the wrong statement;

    • @gustavoholo1007
      @gustavoholo1007 Před 6 měsíci

      Did you study electrical engineering metal? I didn't expect you here I like your videos

    • @monad_tcp
      @monad_tcp Před 6 měsíci

      what's not error prone in the C language of making errors?
      Oh, I should have more respect. I meant.
      Fastly making errors as fast was humanly possible.

  • @larjunmnath
    @larjunmnath Před 6 měsíci +5

    Man you are the sole reason why I fell in love with assembly, couldn't thank you more.

  • @shadowchasernql
    @shadowchasernql Před 6 měsíci +23

    In general as a rule of thumb, I try to keep GOTOs in the same function scope, so just for loops and the like, it helps keep GOTO reasonably easy to read (and far safer!) but also still gives it a lot of flexibility. Also if I'm writing optimized code, I try to keep branches in general (not specifically GOTOs, they just tend to get messier), to be short and minimal, only things like small if statements, just to avoid the LOADS of cache misses you can cause by putting everything in their own function.

    • @NYKevin100
      @NYKevin100 Před 4 měsíci

      Note that in C, goto cannot be used to jump into a different function (mostly because it would be unclear what should happen when that function tries to return). You can use longjmp to do that, but only if the function is already on the call stack (i.e. it behaves a little bit like throwing an exception, but without proper language support).
      My advice is to avoid using backward gotos (prefer writing a loop), and to only use forward gotos to eliminate excessive nesting of if statements or duplicate code. Hand-constructed goto loops can be very difficult to understand, and simple if statements are usually more readable than if-goto compounds.

    • @valseedian
      @valseedian Před 3 měsíci +1

      goto has one really important use for me that aligns with this- it's one of the only ways to short circuit out of a large nested loop algorithm without having to explicitly end each loop.

    • @xwtek3505
      @xwtek3505 Před měsícem

      Is there a language that allows goto to a label in different function scope?

    • @valseedian
      @valseedian Před měsícem

      @@xwtek3505 c++ (at least the mingw compiler from experience, but I think any flavor) can do goto from any point to any other point and can cross scope. it is almost always undefined behavior to goto from one scope to another. notable
      examples of where it can be used is as a return from a void function to the main scope, calling into a function that returns void and uses no arguments, but you have to goto back out, and, it can be used to navigate self altering code if you have the balls to write it.
      I will use goto to leave nested loops if there's no good way and I'm relying on local variables heavily in the destination rather than refactoring it into a referencing function.
      c++, and c, will let you do all kinds of crazy bs. almost every combination of characters that compiles will result in a crashing program. it takes very specific sets of characters to result in a stable execution.
      there are many things you can code in c that will result in an undefined behavior, but a repeatabe result, and that gets used for what it actually does, whatever that is. if you want a Lang that doesn't spit out an executable if it has undefined behavior- go use rust and run into compiler walls

    • @valseedian
      @valseedian Před měsícem

      @@xwtek3505 yes, c, c++ both allow you to goto between scopes. it's practically always undefined behavior. notable exceptions are as quasi function calls but you need to save the origin, and self altering code, if you have the coconuts
      --at least the mingw compiler will allow you to compile with these using certain flags.

  • @oglothenerd
    @oglothenerd Před 6 měsíci +131

    Looking at C code where you check the return type to see if it is an error makes me so thankful that Rust has Option, and Result enums.

    • @kevinyonan9666
      @kevinyonan9666 Před 6 měsíci +27

      What advantage is that? You still have to check if it errors. Plus, you could make your own Result type from an inlined tagged union

    • @shadamethyst1258
      @shadamethyst1258 Před 6 měsíci

      ​@@kevinyonan9666You only have one way to check for error in rust, instead of checking for `NULL`, `-1`, `VALUE_ERR`, or whatnot, and then reading the `errno` or whatever mechanism is used to know what the error was. In rust you just add a `?` or you use one of the error handling methods provided by Option and Result - with most of them sharing the same name across the two types.

    • @TheSast
      @TheSast Před 6 měsíci +6

      Agreed, can't live without them.

    • @oglothenerd
      @oglothenerd Před 6 měsíci +24

      @@kevinyonan9666 The compiler warns you when you haven't taken care of a Result enum, and it also can only represent Ok() or Err() as its variants.

    • @user-vu8fm5vb4n
      @user-vu8fm5vb4n Před 6 měsíci

      ​@@kevinyonan9666you are FORCED to handle the errors or else the compiler refuses to compile your code.

  • @deedoubs
    @deedoubs Před 5 měsíci +50

    Goto is fine, just don't go up.

    • @MrAB-fo7zk
      @MrAB-fo7zk Před 17 dny +3

      You're 100% right .. Read any major projects that power major infrastructure (all C... Hmm) ... You'll see lots of goto, always down to an error condition. It's a pretty common trope in C. Nothing wrong with it.

    • @deedoubs
      @deedoubs Před 17 dny +2

      @@MrAB-fo7zk Not *always* down to an error condition, sometimes you just want to skip over a block of code because a condition is met and it's cleaner than nesting that block within a large if clause.
      Bottom line though is that as long as you are using it to move down from where you are at the same level of brackets, you are absolutely fine. It only gets sketchy when you start using it to go up (IE creating a loop) or to the right (IE you are jumping into a condition or a loop). That's where people start getting themselves into trouble.

    • @MrAB-fo7zk
      @MrAB-fo7zk Před 17 dny

      @@deedoubs you're right, I meant to say just "usually" for an error condition, not always or that it must be for that purpose!

  • @Zullfix
    @Zullfix Před 6 měsíci +25

    Thank you for making this video.
    Many people always scream at the sight of a goto without considering how it can be beneficial to the circumstance.
    I personally write C# more than anything else so I benefit from 'using' statements, however I still find gotos can be very useful when writing state machines or non-LINQ filtering logic.

    • @kuba4ful
      @kuba4ful Před 3 měsíci

      In everyday's code I barely use goto, but when doing code challenges like LeetCode or CodeWars using C# where I tend to stay away from Linq (it's slow + it trivializes some challenges), that's when "goto" statement feels the most useful. It's more efficient both space-wise and time-wise.

    • @captmcneil
      @captmcneil Před dnem

      This has little to do with 'using' - in C goto may be helpful because it lacks control structures like try-finally and its APIs rely so heavily on return codes. Which is a nice way of saying that C lacks proper tools for certain things, and goto is just the lesser of a bunch of evils. But that does not make it good or safe. When you have a language that gives you better options, use the better options.
      Goto breaks structured programming, and static analysis tools can't do their job properly without being able to make strong assumptions about the program flow. In C that may not be a big deal because you cannot make these kind of assumptions to begin with. But in modern C# static analysis is a big advantage. Tools rely heavily on knowing when something has been initialized and not, for example. In my experience many C folks cannot even appreciate that to its full extent because they have no experience with it. It would be foolish to compromise that just for something that might optimize the odd case by a few lines - and this is the reason why goto gets banned in so many projects.
      Please note, it's not at all about whether goto is sometimes useful. It's about principles: If a feature is a bit useful, but sometimes dangerous, and there is another option - always use the other option. Don't argue with me, Douglas Crockford says that a lot, and he's probably smarter than most people here.
      If you ever find yourself writing programs that look like that in Java or C#, step away from the computer. I don't argue about C, but as a senior lead developer and architect with 25+ years of experience, I say this with confidence: I have not seen one justifyable reason to use goto in C# application programming. Not even in 3D visualization or device driver code for industrial hardware.

  • @jbird4478
    @jbird4478 Před 6 měsíci +3

    This is basically the goto solution (pun intented) for handling errors in the Linux kernel.

  • @Anubis1101
    @Anubis1101 Před 6 měsíci +3

    yea people who unilaterally dismiss a basic thing like goto as bad just make it harder and more confusing for new programmers to figure out how stuff works and what they should be doing.
    everything has a purpose, and most things have good and bad ways to use them.

  • @BlitterObject
    @BlitterObject Před 6 měsíci +72

    Finally someone (else) that shows evidence where goto's are useful. Folks, goto's aren't evil; they're just another tool in the toolbox to use when it makes sense given all of the factors. (Singletons in other languages are similar in this way.) Having said this, part of determining "when it makes sense" is to not take it too far and abuse it.

    • @franciscofarias6385
      @franciscofarias6385 Před 6 měsíci +6

      People want shorthands that let them avoid thinking. Every tool is an asset, and you should have better reasons to use them or not than "someone told me so".

    • @loc4725
      @loc4725 Před 6 měsíci +5

      *"not to take it too far and abuse it"*
      I've been having some discussions with some Python programmers and they've been suggesting doing things like using the exception system for things other than raising and handling exceptions. It was a good reminder as to why things like GOTO are considered bad practice - if you metaphorically give some programmers a gun they will eventually shoot themselves.
      That said, GOTO in the event of an unhandleable exception in C is probably itself an acceptable 'exception' given the lack of a formal mechanism.

    • @anon1963
      @anon1963 Před 6 měsíci

      ​@@loc4725if you give anyone a gun* there

    • @jbird4478
      @jbird4478 Před 6 měsíci +3

      @@loc4725 Using exceptions for other things is very common in Python. You'll often see usage of 'KeyError' for example when something not being in a dictionary is just a normal expected state. I don't like it (but I don't like most of Python), but it's not a reason to ban exceptions from Python. Likewise, misuse of the goto statement is not a reason to ban it. You should just accept that some programmers will shoot themselves in the foot. There's no such thing as a good and also idiot-proof programming language.

    • @loc4725
      @loc4725 Před 6 měsíci +1

      ​@@jbird4478 There do appear to be quite a few, I guess you could call them 'mistakes' in Python. Looking at it's development history is like watching people learn what makes a language good / bad but with little knowledge of what came before and why certain features were dropped, added or made that way.
      Also I wouldn't "ban" exceptions and neither did I say that was a good idea. My problem stems from experience of how certain language features or paradigms end up being a problem because you cannot trust many programmers not to abuse them. And yes I agree, all you can do is limit the damage but then that is what a good high-level programing language should aspire to do. It shouldn't needlessly place scalpels on the dinner table or worse, force people to use them because there's no other choice.

  • @sinom
    @sinom Před 6 měsíci +62

    In pure C stuff like this is an at least decent to good way of handling things.
    In most other languages you should rather use some sort of scope guards though (something RAII-like like objects in C++ and rust, or "using" resource statements in C# etc.)

    • @pheww81
      @pheww81 Před 6 měsíci +3

      And even if more modern low-level-like-c language like Zig where you don't have RAII (because no dtor) they added the statement defer and errdefer exactly to avoid this kind of code.

    • @BrotherCheng
      @BrotherCheng Před 6 měsíci

      I think in C++ goto statements are also more complicated due to it being difficult to reason about RAII and object lifetimes in goto. At least I don't remember off the top of my head what the behavior is and I think a lot of programmers don't.

  • @4115steve
    @4115steve Před 6 měsíci +10

    Please consider making the course at one time payment. I think you would get more people to sign up. Thanks for making videos my main man

  • @marshallscarpulla3032
    @marshallscarpulla3032 Před 6 měsíci +25

    I always love this argument. Writing high level code without GOTOs creates more readable code. This is mostly true. The funny part is, the compiler generates tons of jumps (gotos) in the final binary, the actual assembly language. Just disassemble a switch statement, or if-then-else. JMP (goto) is there.

    • @iWhacko
      @iWhacko Před 5 měsíci +9

      just because the compiler does it for you doesn't make it a good practice. Source code is meant to be readable, so make sure it is. If it wasn't we would all be programming in binary. Because that's what the compiler ultimately makes of it.

    • @marshallscarpulla3032
      @marshallscarpulla3032 Před 5 měsíci

      ​@@iWhacko ​ @JodyBruchon
      I think you replier's are missing my point. I've written code with high-level, mid-level, and low level languages for 35 years on a variety of embedded platforms and various computer systems and have always followed the standards of well written, highly commented code as every programmer should, so I will repeat this one little part again. I still find it funny that so much emphasis is put on NOT using gotos in code, even though the compiler has NO choice but to put jumps/gotos into the code at the BINARY level to make things actually work. So, at the lowest level, this no goto philosophy is bunk. Really good compilers do take into account the number of times an instruction cache would be cleared from branches, jumps, calls, and the level of optimizations selected during compile time can mitigate this problem. Some of the compliers are really really good at this, by actually counting instruction cycles and choosing the shortest paths. The bottom line is this. Assembly language can not exist without a jump instruction, but high-level/mid-level code can exist very happily without any goto statements.

    • @gloowacz
      @gloowacz Před 3 měsíci

      ​@@iWhacko " Source code is meant to be readable". I have always stand on position that the source code is meant to create efficient and error-free binary. Readability is secondary. I have experience in nightmare projects that were killed by "good practices" and "code standards" and "clean code". Classic "measure becomes a goal" cases. Deadlines? Don't care, havta extract 5 more interfaces that will only ever have 1 implementation. Performance? Sorry, too busy renaming half of the functions in the project by adding "get" in front of the name. Bugs? Can't help, i am injecting 78th undebuggable maven dependency that obscures the logic behind reflection.
      Meanwhile i was able to recreate 80% of the project from scratch on my own spare time, using 50 classes that compiled in 10s. Not 2000 AbstractIntgerStringPrinterFactory classes that compiled for 15 minutes because of 2 GB of maven dependencies. But it was all "good practicies" while my code was too "tightly coupled" so they went with continuing the garbage. Project went under because of poor performance, bugs and crossed deadlines. Imagine my shock.

  • @leightonmitchell2564
    @leightonmitchell2564 Před 6 měsíci +73

    I was writing a parser, and I used goto because I wanted to break out of the switch statement inside a for loop. It was an elegant solution.

    • @georgehelyar
      @georgehelyar Před 6 měsíci +5

      Another way to do this would just be to put it in a function and return out

    • @CottidaeSEA
      @CottidaeSEA Před 6 měsíci +18

      @@georgehelyar Yes, but there's also no reason to pollute your interface with more functions if there is only one user of said function. One of the reasons why goto has become this hated thing is because goto was the cool thing to do at one point, which just sucked ass when done on a larger scale and very long jumps. Doing it to break out of nested loops or similar is totally fine.

    • @js46644
      @js46644 Před 6 měsíci +3

      ​@@CottidaeSEAwhy would an additional function necessarily be part of the interface?

    • @CottidaeSEA
      @CottidaeSEA Před 6 měsíci

      @@js46644 How would it not be? If you suggest making the visibility private, reconsider that thought and think about what an interface is. I do not mean the keyword interface you're probably thinking of.

    • @keris3920
      @keris3920 Před 6 měsíci

      @@js46644 I agree with you, there is no reason to make the function part of the interface. It should just be a static free function, a private static member function, or not exported from a module.

  • @kuhluhOG
    @kuhluhOG Před 6 měsíci +9

    Imo discussing why GOTO is shunned without talking about what it actually was when "GOTO considered harmful" was written does the discussion a misservice.
    So, GOTO at the time a lot more powerful than what C is able to do. It was not only in most languages the primary way of handling control flow, it was also able to jump across function boundaries. Here an example (in C syntax because reasons):
    void f(int i) {
    label:
    print(i);
    }
    void g() {
    goto label;
    }
    This lead to the problem that you couldn't think of function like a black box. You needed to know what it does if you want to reason about your code. And because EVERY function was able to do that, you needed to practically know the contents of EVERY function.
    And guess what, stuff like this was so widely done, that at the time "GOTO considered harmful" was published it was highly controversial ("You want to say I am not capable of doing this safely?").

    • @Optimus6128
      @Optimus6128 Před 3 měsíci

      That's good to know, I didn't consider it used to work like this. I was always under the impression that the label has to be in scope, so it's not easy to abuse it. Maybe in older versions of C and compilers without following the standards. And the article would make sense then if people did this regularly. I don't even know how that would work, because if in your example g() jumped to label in f(int i), then what the hell is the value of i at that point? Why would anyone do that even if allowed?
      But thinking about, we have much worse things nowadays that will actually break the flow, something inside scope affecting things outside scope even without you realizing it.

    • @xwtek3505
      @xwtek3505 Před měsícem

      I can't imagine how the code snippet should do other than undefined behavior

    • @kuhluhOG
      @kuhluhOG Před měsícem

      @@xwtek3505 as I said, in C it would not even compile
      in the languages back then? well, UB wasn't really termed well yet and everything not otherwise defined was "implementation defined behaviour"; so, yeah, it worked because programmers looked at what the implementation actually did, and then used that to their advantage
      not with undefined behaviour, that's not really possible anymore since what is being done under the hood is more often than not unpredictable
      I would argue that we are worse off know in that department
      nonetheless, goto thankfully can't jump outside of functions anymore

    • @Stratelier
      @Stratelier Před 22 dny

      I think scope restrictions are a major part of why GOTO got deprecated to begin with. Even at the lowest level, if you GOTO a code point that's inside a different function scope, then it encounters a RETURN (without having first called said function in the usual manner) the return address it pops from the stack may be anything from unpredictable to actual garbage -- likewise, references to local variables pushed onto the stack may return unpredictable/garbage values.

    • @oddcraft18
      @oddcraft18 Před 22 dny

      Bro u need goto ur gonna miss out on 0.1us

  • @Minty_Meeo
    @Minty_Meeo Před 6 měsíci +28

    My favorite use for goto in *C++* is to mimick the for-else pattern from Python. For the unaware, else statements on for loops will only execute if the loop concluded by its condition, rather than a break. With iterator-based for loops, it's as simple as moving the condition inside the loop body and turning it into a break (that way, you can add additional code to that specific exit path). For range-based for loops, that is not an option. Instead, the solution is to replace all breaks with gotos which skip past a block of code immediately following the for loop's scope.
    for (const auto& v : container)
    {
    if (some condition)
    goto LOOP_EXIT;
    SomeFunction(v);
    }
    std::println("All good!");
    LOOP_EXIT:
    ...

    • @dontthrow6064
      @dontthrow6064 Před 6 měsíci

      Nice concept. Like when you have a piece of puzzle that almost fits and then you find the real piece.

    • @LittleRainGames
      @LittleRainGames Před 5 měsíci +1

      Oh wow, didnt know that about for loops. Great to know

    • @PalladinPoker
      @PalladinPoker Před 5 měsíci

      you could also do the following and skip using goto, although goto is cool.
      uint16_t i = 0;
      while (i < loop_range && !(some condition))
      {
      SomeFunction(i);
      }
      //destroy i

    • @Minty_Meeo
      @Minty_Meeo Před 5 měsíci +1

      @@PalladinPokerI don't think that code does anything like what I wrote, but I think you were trying to suggest using the loop counter from outside the while loop's scope to detect if it terminated before reaching the loop_range? GOTO doesn't require an if statement to check the loop counter after the loop concludes, so GOTO is still better if that's what you're trying to suggest.

    • @gayusschwulius8490
      @gayusschwulius8490 Před 5 měsíci

      @@PalladinPoker That's WAY more inefficient due to the additional call and check, even more so if the outside function isn't inlined.

  • @captainfordo1
    @captainfordo1 Před 6 měsíci +3

    Another use of goto is for breaking out of a nested loop.

  • @MarioDanielCarugno
    @MarioDanielCarugno Před 6 měsíci +2

    Once upon a time I worked like that.
    We called 'epilogue' to labels at the bottom of each function to handle cleanup and having a single point of return.
    When goto was considered a 'bad word', exceptions were invented.
    Great video to remind that goto is not so bad, thank you

    • @monad_tcp
      @monad_tcp Před 6 měsíci +1

      bool do_something_unguard(int *f) { }
      bool do_something() {
      bool b; int f = open();
      if (f) b = do_something_unguard(f);
      close(f);
      return b;
      }
      // this gets boring fast, so does "goto exit:;"
      // its almost like there's a reason for try/finally to exist...

  • @apresthus87
    @apresthus87 Před 6 měsíci +7

    This is the first time i've ever I just instantly went and bought a course from a CZcamsr as soon as you mentioned the C course. I fell in love with C after years and years of using higher level languages but learning materials were a bit sparse so I'm super excited for this even though I'm not a beginner in C, I'll learn a lot I'm sure! :)

  • @TheGrimravager
    @TheGrimravager Před 4 měsíci

    Hey man, this is really cool.
    I wanted to compare the code before and after the goto statements.
    I wanted to check if a function call with a little refactoring wouldn't be an even better improvement, completely dropping the goto. A link to a gist or something would have been incredibly helpful for that.

  • @emmiasilk9059
    @emmiasilk9059 Před 6 měsíci +3

    Interesting. For the example you used as a good usage for a GOTO, I think the step-of-error-handling functionality *could* be reproduced using a switch statement instead (by passing in a value representing which step you are on, and letting that decide the starting point). But I think then use of a goto would make it more readable.
    Still, I can't help but wonder if there's an even more elegant way of dealing with this kind of circumstance.

    • @anon_y_mousse
      @anon_y_mousse Před 6 měsíci +1

      In this instance, while I love C and I still think it's the best language, C++ actually provides a more elegant solution whereby the cleanup code goes into the destructor for a class so that if any part fails you could simply return from the function and the appropriate cleanup would occur. Even though I borderline hate Zig for the syntax choices they've made, I'll admit that defer is also a rather nice option and slightly more flexible.

    • @bbq1423
      @bbq1423 Před 6 měsíci +1

      In more recent languages there is defer and sometimes errdefer which does essentially the same thing. In languages with lambdas and destructors you can synthesize defer by creating a type with a constructor that takes a lambda and a destructor that runs the lambda.

  • @hyper_lynx
    @hyper_lynx Před 23 dny +1

    Just now learning that goto and longjump are different. I always assumed the issue with goto was that it does what longjump does and lets you jump into a different function with the wrong stack setup

  • @alexandreparent3942
    @alexandreparent3942 Před 6 měsíci +2

    And that's why we have C++ and RAII. No direct close. Things are released as it goes out of scope.
    If we don't want that... What about... Functions? They are gonna be inlined by the compiler.
    You could even not use early return and instead have the positive case in the if statement. Then cleanup is not duplicated.
    3 alternatives to goto. Each with downsides. Each way more readable than goto.
    My main issue with goto is not even the obfuscation, it's scope switching.
    And that's not even considering you can goto a label inside another block to get some neat italian pasta.

    • @TheRobbix1206
      @TheRobbix1206 Před 6 měsíci

      That's because it was designed with C Ansi in mind which ask you to declare all your variable as the start of the function preventing any scope changing shenanigans

    • @sub-harmonik
      @sub-harmonik Před měsícem

      I disagree with 'more readable', you're just introducing more control flow structures that actually make things less clear sometimes.
      for instance, you say use the positive case. but what if the 1st resource is positive but the second isn't? then you want to goto the negative case of the 1st resource to clean it up. (and actually that's the case in his example)

  • @jordixboy
    @jordixboy Před 6 měsíci +13

    If, while, for, underneath they are just "gotos"

    • @Proferk
      @Proferk Před 6 měsíci +15

      in that analogy, everything in C is just syntactic sugar for the inline asm statement.

    • @fders938
      @fders938 Před 6 měsíci +3

      ​@@Proferk Hey, that's why C is just a macro assembler, right?

  • @azaleacolburn
    @azaleacolburn Před 5 měsíci +1

    Love the ioccc approximating pi reference!

  • @thebuffman5597
    @thebuffman5597 Před 6 měsíci +59

    I remember in our first C# class the first task the teacher gave us was "make a loop".
    I proceeded to write a goto variant for it with a break i made, the teacher was impressed but was like "okay, but please do the other way as this one is illegal" xd.
    The reasoning explanation he had made was that unlike regular loops, this would make a randomized selection or something and that it would result in slower program in a sense.

    • @lycanthoss
      @lycanthoss Před 6 měsíci +13

      I don't understand what your teacher meant to say, but you should absolutely not be using gotos in C#.
      If you have to use a goto in C#, it is telling me one thing about your code - your function is too big and needs to be split into multiple functions.

    • @thebuffman5597
      @thebuffman5597 Před 6 měsíci +15

      @@lycanthoss Lol, I just said the teacher also said it was suboptimal, but he was surprised someone even knew about it, because people usually learning languages like python nowadays, etc. don't really learn this stuff at first.
      It was back when i started learning and wanted to be a bit funny. Like yeah, it's not a good way, but a funny way nonetheless to make an infinite loop.
      I'd never use it under normal circumstances. After asking around the only place where i could find use for gotos is maybe in kernel programming or so.

    • @insomnyawolf
      @insomnyawolf Před 6 měsíci +1

      As some people already pointed out, they are just another tool in the box, and i am thankful for having them on C#, they are very rarely the way to go but it can make things a lot more clear and simple when used properly, but normal programmers rarely have the need.
      For me i find it very useful for conditional retry logic and for exiting nested loops those cases are kinda rare.
      You could argue that my code sucks then, but in that case i would like to learn a better way to do those that still work without overcomplicating simple things

    • @spearmintlatios9047
      @spearmintlatios9047 Před 6 měsíci +1

      What your teacher was probably talking about is ASLR, which randomizes addresses. This is implemented to prevent malicious attacks that tells the program to jump to an arbitrary line of code. If the attacker cannot be sure of the exact address of their desired code, then they cannot reliably execute arbitrary code or steal data.

    • @mage3690
      @mage3690 Před 5 měsíci

      The reasoning sounds like hocus pocus to me, why you _really_ shouldn't use it is because it makes everything harder to reason about. You could use a goto to implement ifs, fors, whiles, and functions, but just using the keyword designated for that purpose frees you brain up from having to follow the goto chain to figure out which one it is. Freeing up those mental clock cycles makes it easier to figure out whether or not your code goes into an infinite loop or any other bad state _before_ running it and having to use the debugger to figure out WTF is going on.

  • @CottidaeSEA
    @CottidaeSEA Před 6 měsíci +9

    I don't mind goto at all, but I think it should only be used in a very small scope. I think you can usually get a similar result through creating functions, so there is little need to actually have goto, but imagine you're searching for a specific value in a larger function and you have multiple nested loops for whatever reason. At that point you might actually want to have a goto in order to quickly break out of all loops. That is a perfectly valid use case in my eyes. The label is close enough to the goto for things to be understandable enough and you avoid having loads of breaks and if-statements. Could you just have made a function and returned the value when finding it? Sure. But sometimes you don't want to create a new function as it is not really a necessity in your use case. The goto will also be faster than doing if-statements every loop that break if true, which can matter a lot for larger data sets.
    So as long as you keep things simple enough, I think using goto isn't bad. Just don't do a bunch of branching logic with them. Only use them as fast exits out of nested loops and such and you're all good, avoid them if necessary though.

    • @xeridea
      @xeridea Před 4 měsíci +1

      Breaking nested loops is the pretty much the only reason I see to keep goto around. There are some other possible very niche uses, but generally this can be improved by refactoring code to be cleaner. In this video, he turned 13 lines of code into 17, and made a mess out of it.

  • @SolidFake
    @SolidFake Před 5 měsíci

    Cool, might actually make use of this in work next week. I had the issue that my C-code was too large to flash it on a microcontroller, and one thing I recognized was that I had such error-checks where each succeeding one only adds a line or two. Might give it a go (to).

  • @jongeduard
    @jongeduard Před 3 měsíci

    I fully agree! This is great code. I do not write C too often, but I have been correcting some of my own code similarly to this. Albeit with a break statement in my case.
    The point is to not write any more resource deallocation lines than allocation lines, as a good practice. In order not to accidentally leak resources or create duplicate frees.
    As soon as you allocate stuff, you do not want to diverge. All code paths should come together at the end of your code.
    It's good te remember that C is a low level language and does not have any try finally constructs or RAII features. And there's no GC. It's not a functional programming language where you can always do lots of return statements without any worries.

  • @TrOllOchamO
    @TrOllOchamO Před 6 měsíci +2

    Just pointing out a little error in the first version of the error handling code. You should call perror first before calling any function that could set errno. In this case the error message won't be very helpful since it will print the termination message of the close function instead of the malloc error.
    Great video 😁

    • @lunlunnnnn
      @lunlunnnnn Před 6 měsíci

      Not like it really matters, the point of the examples was to demonstrate a good usage of goto, not to show perfect code

  • @AterNyctos
    @AterNyctos Před 6 měsíci

    That last case you mentioned (the good use of a goto) feels like a switch statement in a way.
    I supposed as most languages I use don't have goto, I'd increment or set a numeric variable and then switch() it for error handling.
    Great video! I learned a lot :)

    • @gregorymorse8423
      @gregorymorse8423 Před 6 měsíci +1

      Interestingly with a switch in a loop or loop in a switch, break and continue operate differently.

    • @AterNyctos
      @AterNyctos Před 6 měsíci

      @@gregorymorse8423 Huh, didn't know that.
      Cheers!

    • @gregorymorse8423
      @gregorymorse8423 Před 6 měsíci +1

      @@AterNyctos yes break in switch always breaks the switch. But continue in a switch effects the loop. Weird aspect of C syntax

    • @gregorymorse8423
      @gregorymorse8423 Před 5 měsíci

      @@JodyBruchon you obviously are extremely ignorant. Switch statements are jump tables except for ones with only 2 or maybe 3 branches. You literally have no idea of how modern processors and compilers work. You've given serious evidence.

    • @gregorymorse8423
      @gregorymorse8423 Před 5 měsíci

      @JodyBruchon maybe I'm being a bit harsh but seriously Wikipedia "branch table". Practically speaking this knowledge is important though with a good compiler perhaps it needn't be.

  • @drkspace
    @drkspace Před 6 měsíci +5

    Another good use case is if you're in a nested for loop and one of your inner loops needs to break out of the entire thing, instead of having a bool that propogates breaks up the loops, you can just have a goto that leaves the entire structure.
    I'm not sure, in c++, if this'll work with scoped variables, so that might be a case where you don't want to do it.

    • @ChapmanWorldOnTube
      @ChapmanWorldOnTube Před 6 měsíci

      In this case, why would you not move all of those nested loops to their own function and simply return from it when you need to break all of the loops?

    • @WindLighter
      @WindLighter Před 6 měsíci +1

      @@ChapmanWorldOnTube there might be a necessity to use a bunch pf local variables withion the structure, so you will need either to use global variables instead, that makes bug probability higher, or put all those stuff as a parameters into a function that is called from a single place of your code and depending on compiler that may cost you some perfomance and memory. Also the function will be stored at a different place in your code so you will actually need to spend extra attention to keep track of what is going on, so in this case a simple jump to a lable makes code actually cleaner and better in both readability and perfomance

    • @ChapmanWorldOnTube
      @ChapmanWorldOnTube Před 6 měsíci

      @@WindLighter I of course don't share the same coding style or habits that you do, and I also don't code in C typically, so I hope you won't read it as confrontational that I disagree...
      Of course any call to a procedure/function is a performance concern, however, IMO making function calls is far more unfairly demonized than go-to.
      Function calling is a performance hit of a few milliseconds, which of course matters if called repeatedly in a loop - but presumably moving all of the nested loops within the isolated function means you need call it only once to initiate it - or at most, once per cycle of an outer-most loop.
      In terms of readability - yes, when reading the calling code you might have to go locate the function elsewhere in the source code - a small chore should you need to. However, if the function is well named, in many cases you may be able to read past it without being concerned. In addition, I find locating and reading separate functions to be far easier than the alternative - one long sprawling list of nested loops gives me shudders. I envisage functions growing to many pages (and have worked on such code bases), and would very much prefer to have to go find a function, rule it out in terms of relevance, and return to the calling function to continue reading.
      Parameter passing - If there are many local variables to pass then this could increase that function call overhead a little, but it also indicates a possible design flaw. Could the state information be wrapped up in a struct, which could be passed by reference? This isn't a cop-out, saying just pass a struct, but rather, all of those local variables must be logically relevant to each other (in abstract terms) to be required in the nested loops, and therefore could be conceptually combined into a struct representing the computational state, and with a suitable name to reflect what that is. From this the very concept of OOP falls forth.
      Ultimately, goto is an individual choice or preference, but I feel if you're going to use it, it should always be a prompt to reconsider, is your abstraction of the problem a good abstraction.

    • @anon_y_mousse
      @anon_y_mousse Před 6 měsíci

      @@ChapmanWorldOnTube The problem with that solution is that you then must unpack the variables from the struct. Whether they're passed on the stack, and thus take up valuable stack space, or passed by address while contained in a struct, it either requires extra space to be used up or extra syntax to be had. Both solutions are less easily understood at a glance, more difficult to type in, and potentially fraught with extra bugs, on top of requiring extra copying of values which in a long-running loop will add up. Now, if the compiler optimizes said functions because you label them static and use -O3, you still have harder to grok code with more potential for bugs.

    • @ChapmanWorldOnTube
      @ChapmanWorldOnTube Před 6 měsíci

      @@anon_y_mousse We are clearly coming from very different places. I think I hold the opposite position on every point that you made. I don't code C anyways, I have never really liked the syntax. I have always been more in the Writhian camp. I will bow out on a mutual disagreement on this one.

  • @D0Samp
    @D0Samp Před 25 dny

    Also if you're using C++, the compiler cleans up if you use goto to leave an inner scope just like with other control flow statements, but it may leave variables in an ill-formed state if you go past their declaration.

  • @Stratelier
    @Stratelier Před 6 měsíci +1

    I remember even in late Visual Basic programming, there were sometimes esoteric cases where I actually resorted to those old GOTO/GOSUB statements. For example, VB doesn't have a "continue" feature inside loops, so if I needed to do that I'd label the end of the loop (e.g. "ContinueHere:") and GOTO that point.

    • @Hublium
      @Hublium Před 6 měsíci

      It also specifically had the language feature "On Error GoTo ..." for the use case similar to the one shown in the video.

    • @Stratelier
      @Stratelier Před 6 měsíci

      @@Hublium Yup, I remember using that. Especially when dealing with file I/O. A bit more dangerous was the "On Error Resume Next" which was super convenient if you needed to test just one call that might error out, but you had to remember to turn it off again (On Error Goto 0) or you've just suppressed all runtime errors globally until program execution terminates, potentially opening up all kinds of glitchy misbehavior downstream. Have fun debugging THAT!

  • @ProjSHiNKiROU
    @ProjSHiNKiROU Před 6 měsíci +4

    For high-level language designers, thye must learn from examples where goto is essential in C and design features to avoid the need for goto, such as auto-dispose resources (RAII in C++ and Rust and using C#), or hand written state machines (async/yield).

    • @monad_tcp
      @monad_tcp Před 6 měsíci +2

      The goto is literally not needed for any case whatsoever, in 20 years I couldn't fine any. Except the funny looking DuffyMachine, which is not even valid performance optimization anymore.
      Well, jumping from a statement to another in a switch would be a legal use for "goto", but you don't need it, just put the switch inside a for-loop and change the expression of the switch and do "continue".
      Hand written state machines can be created by mere function calls if you have a fix-point function to break the call-stack from becoming infinite. Its a common technique in Lisp. Maybe C programmers don't know that. Or maybe their compilers are too dumb to do RVO, aka, Return Value Optimization.
      Something akin to a ".tail" for that in its IR. (almost all virtual machines that are JIT compilers can do that, its kind of a trivial optimization)

    • @int32_
      @int32_ Před 6 měsíci +3

      @@monad_tcp it's not needed, but it can make your code prettier and less repetitive in some rare cases (the linux kernel often uses gotos for error paths)

    • @monad_tcp
      @monad_tcp Před 6 měsíci +1

      @@int32_ yeah, that's a well know deficiency of the C language.
      that pattern is so used that compilers can actually do semantics analysis on it and I'm going to even admit that its the only valid use for goto.
      besides jumping to another case in a switch which is a neat misuse of goto that does work and very little people know you can actually do that.

    • @vitalyl1327
      @vitalyl1327 Před 5 měsíci +1

      Impossible. Goto is essential for representing irreducible CFG (for all procedural constructs are, by definition, reducible). Which means, pretty much any mildly complicated FSM, including all kinds of parsing and tree walking. Languages without a goto are crippled languages.

    • @vitalyl1327
      @vitalyl1327 Před 5 měsíci +1

      @@monad_tcp lol, now try to implement an efficient indirect threaded code interpreter without a goto.

  • @CallousCoder
    @CallousCoder Před 6 měsíci +1

    I always found it an academic discussion. Because as you and I know in assembly a goto (jump) is required.
    But in the extension of this discussion also was the “one return per function” something I break all the time these days.

    • @gregorymorse8423
      @gregorymorse8423 Před 6 měsíci

      Maintainability of code isn't an academic discussion. I'm sure everyone at your work place loves your spaghetti code lol

    • @CallousCoder
      @CallousCoder Před 6 měsíci

      @@gregorymorse8423 you may not have watched this video then. The goto must go idiom is obviously not correct there are use cases where goto is a superior solution. Hence the clean code is not objectively true. And I can prove it even further, as jumps are Gotos and are the backbone of branching on a machine level. So the whole “clean code” religion breaks down the lower you go.
      Just like the idiotic “one return per function idiom”. It makes code unnecessarily more complex and slower.
      Then the “though shalt not repeat thyself” which is something you generally should stand by, but I have had situations where unrolling code is faster. And when there’s one situation where your “religion” doesn’t apply you can’t not should preach it as a fact.
      And “spaghetti code” what is that?! Is it a jump? Because a call to a different function is also a jump and you need to grab the listing of that code and read it to understand it completely. Every program exists of different strands of “pasta”.
      Ironically you can get far more list in Uncle Bob’s OOP world then a piece of assembly. Because it’s hard to find a single entry in complex frameworks like spring, spring boot, J2EE that have scheduled or event beams or even C++ which spawns many threads or systems with event messages.
      So even “spaghetti code” isn’t an objective truth.
      And it’s also a skill level! I’ve been developing software for 40 years. I find that the last 20 years I find it far easier to reverse engineer code than I did it the first 20 years. Just because I’ve seen more.
      The first time I saw self modifying code, back in 1988 I was like: “wtf? I don’t understand what is happening here. Why is a memory location in code space updates?”
      I spend literally a whole weekend experimenting with it and realized it’s power. And how I could reduce the amount of code needed and speed up for example joystick routines on the C64. Since I’ve seen self modifying code a lot and it’s just a matter of checking to see what opcode is set and it’s clear.
      So yeah, even “spaghetti code” is busted as an objective scientific fact. Unlike ohms law that always is R=U/I or gravity is always 9.8M/sec and doesn’t deviate on Sunday’s or has an exception on Mount Fuji.
      That is an objective scientific proof. It’s merely an academic discussion and personal preference that are not scientific facts. Because there’s an exception on everything Uncle Bob and his predecessors preached.

  • @sorcdk2880
    @sorcdk2880 Před 5 měsíci +1

    I would probably go with nested inversed if statements in a case like this, where instead of a cleanup on failure, you get a choice of continuation or local cleanup, which is then followed by the cleanup. Kind of like this:
    errors = 0
    do buffer thing
    if (buffer succeeds) {
    do socket thing
    if (socket suceeds) {
    do socket use
    } else {
    perror("sucket")
    errors++
    }
    close(socket)
    } else {
    perror("buffer")
    errors++
    }
    free(buffer)
    return 0-errors

  • @speed488
    @speed488 Před 3 měsíci

    I'm working with an SDK of a transaction processing system which uses callbacks to send events. The callback function is essentially a big switch/case statement processing the event the SDK sends. There's one case where I need to process a failed transaction which is executing a function and closing the transaction exactly as the successful case. I've been contemplating using a goto there for maintainability. There's a strong chance the successful transaction case will change in the future and might not get updated the same way in the failure case; the goto would make sure the code is only written once. However, using a goto in a switch/case is quite an anti-pattern.

  • @ThePCxbox
    @ThePCxbox Před 5 měsíci +1

    goto's are very handy in the case of gamedev - specifically when wanting to jump around within nested loops. Makes things 10x faster and organized if you do it right

    • @Rock48100
      @Rock48100 Před 3 měsíci

      Especially for text adventures

  • @strajkz
    @strajkz Před 6 měsíci

    The one place I rather often use goto is in my custom installers, where I skip several steps or log an error and then jump to the end of a function without using a return.
    Yeah I could make function for each step and just do a return in case a bad return code matches, I however like to keep things as less convoluted with methods and functions in installers as possible, which in my past experience makes it easier to maintain.

  • @videakias3000
    @videakias3000 Před 3 měsíci +1

    I remember in highschool the book had an entire page saying how goto is the black sheep of computer commands and mentioned that some guy wrote an entire book against the goto.
    I wasn't taught back then how to use it and I wasn't taught how to use in the electronic engineering tei either(we only learned visual basic and c# there)

  • @RavarYgamer212
    @RavarYgamer212 Před 5 měsíci

    I made a DFS klotski solver, and using a normal recursive function it gave me segmentation fault, but doing the recursive parts with goto worked flawlessly

  • @tjdewolff5104
    @tjdewolff5104 Před 4 měsíci +1

    The proper answer to this code chaos is (hold on tight): nest your code. Yes, you read that correctly: nest your code!
    You started of quite nicely by introducing a return variable. This should ALWAYS be the very first declared variable in your code and set to THE error code, here -1. On success, the inner level of nesting, set it to 0. This saves a whole lot of lines assigning -1 to the error code variable.
    Furthermore nesting provides a perfect way to achieve congruency between scope and lifetime of a variable. Actually it's the only way.

  • @mk72v2oq
    @mk72v2oq Před 6 měsíci +3

    Bad example to be honest. This case can easily be substituted by simply nesting the code.
    Or, if you don't like deep nesting, by function calls. I.e.
    int proceed_with_sfd(int fd, void *filebuf, int sfd) {
    // Do stuff with fd, filebuf and sfd
    return 0;
    }
    int proceed_with_filebuf(int fd, void *filebuf) {
    int sfd = socket(...);
    if (sfd == -1) return -1;
    int retval = proceed_with_sfd(fd, filebuf, sfd);
    close(sfd);
    return retval;
    }
    int proceed_with_fd(int fd) {
    void *filebuf = malloc(...);
    if (filebuf == NULL) return -1;
    int retval = proceed_with_filebuf(fd, filebuf);
    free(filebuf);
    return retval;
    }
    int main() {
    int fd = open(...);
    if (fd == -1) return -1;
    int retval = proceed_with_fd(fd);
    close(fd);
    return retval;
    }

    • @malcolmgruber8165
      @malcolmgruber8165 Před 6 měsíci

      But why risk the cache miss with a function call when GoTo achieves the same thing without the issue.

    • @mk72v2oq
      @mk72v2oq Před 6 měsíci +1

      @@malcolmgruber8165 because this is 1000 times more readable and easier to debug. Following your logic lets write all the code in 1 giant function with goto jumps.
      Not to mention that such small functions will be inlined by the compiler anyway. So that kind of premature optimization quickly becames pointless.

    • @jbird4478
      @jbird4478 Před 6 měsíci

      @@mk72v2oq Honestly, I find this a lot less readable. Now you have 4 functions for a trivial thing, and if you do this with all functions, you end up with a heck of a lot functions, all of which require a sensible and unique name. To follow the control flow I now have to scroll upwards and scan function names, which are going to get progressively worse the more you apply this, and keep track of what each argument actually is. It requires more code that you not only have to write, but also have to parse when reading it. And either way, you just have a single linear control flow with multiple entries to a single linear flow on failure. Except that in this case, both linear flows are scattered in the code.

    • @mk72v2oq
      @mk72v2oq Před 6 měsíci +1

      @@jbird4478 well, it is the nature of C. In practice you usually can do it smarter and shorter though. The main goal here is to restrict area of responsibility of every function.
      The problem with goto that it can be misused very easily. It is even more dangerous than regular unsafe C things.
      But yeah, the language itself is inherently flawed in this regard. C is the last one where goto is even thinkable (if you don't still code in BASIC lol).
      Embrace modern languages if you can. Functional elements make it way more clean.
      Also, when control flow has conditional branches, it is not linear by definition.

    • @jbird4478
      @jbird4478 Před 6 měsíci

      @@mk72v2oq Any programming construct can be misused. It's the nature of C that you can use goto for such situations. And any paradigm can be over implemented. Limiting the responsibility of functions is generally a good idea, but it can certainly be overdone. To open a file, in practice one often has to do a few things more than just calling open(), but that doesn't necessarily mean they all have be separate functions. It can be practical to keep a reasonable amount of things in a single function.
      And you're right of course. I should've put "linear" in quotation marks or something, because what I meant is that if all goes well there's really only one code path. And if you're reading it, that's generally what you want to know first. Then the points of failure are things you follow if needed, but in case that's also just a single path. So regardless of how you write it, what happens here is the code runs from A-Z, except it jumps out on failure. And that's precisely what the version with gotos reflect in the code. Higher languages provide other alternatives for this, like exceptions or scoped destructors, but C doesn't. C provides its own tools, and one of them is goto. Like all tools, there are situations to use it, and situations where you should not, but there's no reason to avoid it at all costs like some people seem to think.

  • @spudbencer7179
    @spudbencer7179 Před 3 měsíci +1

    So in the "good" example for using "goto" I have this question: Why not simply make a method to which I pass the necessary parameters and then call close on them? What's the advantage of the goto in comparison? I might have missed it. But the duplicate code is not a problem to me as I can outsource any duplicate code into a method that gets the necessary parameters and just call that method instead.

  • @LeonAlkoholik67
    @LeonAlkoholik67 Před 6 měsíci +6

    I'm gonna goto hell now

  • @eltreum1
    @eltreum1 Před 4 měsíci

    We have it so good and rough these days. IF and GOTO were the only flow controls we had. There was no malloc or garbage collection. We had to remember the addresses of the ROM and RAM usable memory registers and read/write them directly with PEEK and POKE. You could make a sheet of graph paper into a chart and memory map the entire program and map the execution flow end to end before typing anything if you wanted.
    What's old is new I guess. We started with strict typed languages and mainframes, then we wanted dynamically typed user-friendly languages and our own servers in the enterprise, now we are back on the strict typed language kick and cloud computing as a modern replacement for the mainframe.

  • @rasowa2958
    @rasowa2958 Před 6 měsíci +1

    The very few times when I used GOTO in my C code was always for the reason shown in this video, to avoid duplication of a clean-up code before returning from the function.

  • @marcingardyjan6680
    @marcingardyjan6680 Před 5 měsíci

    In C# your example would be:
    using (open file)
    {
    do something
    }
    that's all. If "do something" fails it will close object that was created in using section - in this example close a file.
    Also similar think you can make with try catch section.
    You can use functions with return.
    Also using break and continue.
    The only reason to use goto is when you want break from double loop. (Loop in a look). Break will exit from one loop only.

  • @garypinkett6275
    @garypinkett6275 Před 5 měsíci

    Even though it goes against everything I thought I believed in… I love this

  • @meoDomicio
    @meoDomicio Před 6 měsíci

    I love the configuration of your vim editor

  • @abuk95
    @abuk95 Před 6 měsíci +1

    I did exactly this for my college project, because using early returns seemed more messy. I realized that 'goto' is not some forbidden practice and this is a valid use-case. Like with breaking out from an inner loop.
    Is this a normal practice to do with C in a professional environment?

    • @thefafala
      @thefafala Před 6 měsíci +1

      It depends. But in embedded C, it's standard practice to use goto (as far as Ive seen)

  • @futuremapper_
    @futuremapper_ Před 18 dny

    I usually only use goto in command line apps where I need to validate inputs. Invalid input? Move back to the line that takes the input. Super simple and readable

  • @Songfugel
    @Songfugel Před 3 dny

    You can use composite functionality to achieve the exact same thing as here without gotos, however, where gotos shine, is making specific jumps out from multilevel iterators (like nested loops) that can get very messy and have to do extra steps without them
    edit: meh, only now noticed this was and old video and others had already commented the same thing

  • @DeathStocker
    @DeathStocker Před 6 měsíci

    Another good use case of gotos is in computed gotos for dynamic dispatch. IIRC a simulator used to use this for their opcode dispatch. I don't know if modern compilers don't need this and can optimize it automatically but I remember it being claimed to be 20% faster

    • @bbq1423
      @bbq1423 Před 6 měsíci

      This is still the case afaik. That thing is using a computed goto, which is not standard, but actually really cool. Reason for it being faster was something along the lines of optimizers optimizing switches inside of loops to small code rather than the longer code with more branches. In this case you'd want many branch sites for the opcodes since the cpu is able to predict the behavior of the opcode code better than a single branch site.

  • @davesherman74
    @davesherman74 Před 3 měsíci

    Grew up typing in BASIC programs on my Commodore 64, and GOTO was very common. When I learned C in college, the course didn't even mention the keyword goto. It was years later that I learned that goto was recognized in C. I can say the ONLY time I ever used goto in C was when I was trying to debug something and used it to skip over a section of code.

  • @apollolux
    @apollolux Před 5 měsíci

    I’ve never seen goto/raw jumps as illegal in whatever language I was using that had them, I just considered the results of their usage to be more _potentially_ uncontrollable or unpredictable and therefore requiring more discipline, foresight/planning, and intention in code than “standard” conditional logic conventions.

  • @m.projects
    @m.projects Před 6 měsíci +3

    retval could have been set to -1 at startup instead of before every goto statement 🤓

  • @agsystems8220
    @agsystems8220 Před 6 měsíci +3

    They are good for state machines in particular. Tail call functions are sort of better versions of them, and the difference is informative. Tail calls need to have context explicitly passed, while gotos retain the same context. This is why goto is so dangerous. When you read a block entered via goto you have no idea of what the context is (neither does the compiler), but responsibility for cleaning up the context is passed anyway!
    We often see weird loop contortions in an attempt to make things that are not loops fit into them, and it really bugs me. State machines are some of the worst offenders, but maps are often maps in a programmer's head, converted to a loop for the code, then converted back to a map by the compiler for vectorisation! Goto is a fantastic pattern for building a state machine where each state is working on the same context, such as parsers. Sure, the control flow is unpredictable, and 'spaghetti like', but sometimes this is inherent to the system you are modelling rather than bad code.
    Goto is a very crude tool, but most languages don't have better ones for non looping control flow. Tail calls are pretty close, but ideally you would want to avoid the function call overhead when you just want to build a state machine. I would like to see dedicated state machine control flow structures, more restricted than goto, but still able to handle non looping control flows elegantly without programmers having to translate it out of the form that it exists in their head.

  • @mattias3668
    @mattias3668 Před 5 měsíci +1

    2:33: No, you print first so you are sure errno is not modified. Now, in this case there is no reason that errno would be modified, but that's not always the case.

  • @mrbutish
    @mrbutish Před 23 dny

    Goto is a must to make code readable, although it hurts readability when used improperly.

  • @mage3690
    @mage3690 Před 5 měsíci +1

    I've only ever used goto in C where I would've used "break 2;" (or any larger number) in PHP. Honestly, I'm 50/50 on which is more readable: "break ;" is more readable in an immediate sense, but "goto breaknum;" is more readable when you want to figure out where things are going, especially if there's a complex nesting going on. Either way, it's better than the JS version, which makes you put the label _above_ the scope, then "break label;": i.e. "forlabel: for () { if () { break forlabel; } }" I get it, you're labeling the scope and then breaking from that scope, but it's still the worst of all worlds.

  • @mirror1766
    @mirror1766 Před 6 měsíci

    I learned to use it as I learned variations of BASIC, some which required it while others strongly benefited from its use for performance reasons in areas where nongoto solutions existed. I corrected various errors in code from both people I knew and didn't on TI graphing calculators due to it actually being used improperly (entering/exiting blocks of code like if statements, loops, etc.). I'd say such improper use is why it could be actually justified as bad as it leads to program bugs, but is still limited to the programmer made a mistake; illegal because 'hard to read' either means the person writing code either uses a very bad style of organizing instructions in the file in the first place, and likely not limited to use of goto, or the person reading it needs to work more on their ability to read code. Readability was the least of my concerns in these cases though I did make improvements there too.

  • @AlFasGD
    @AlFasGD Před 3 měsíci

    Another case I can think of is breaking out of a nested loop without introducing a one-shot flag variable, or likewise continuing the outer loop while inside the inner loop

  • @Nik930714
    @Nik930714 Před 6 měsíci +1

    I've been a C programmer for about 10 years now. By far the most unreadable code i've had to work on was in my first internship. It was for a company that makes quite complex embedded devices.
    The main functionality was in a function that was around 15-16K lines of code. There were maybe 1000 gotos in that with around as many labels. The programmer used C as assembly, so goto was prevalent. From simple stuff like while and do-while loops done with gotos and the entire error handling done with gotos. And like LLL just pointed out, gotos are great for error handling .... Unless your error handler is 1000 lines long and some error states point to parts of previous error states.
    That code was so messy and difficult to maintain that it was part of the reason why i declined a job offer with them.

    • @vibaj16
      @vibaj16 Před 3 dny +1

      goto has its uses, but if you have to scroll miles worth of code to find where it jumps, you're doing something wrong

  • @LogicEu
    @LogicEu Před 6 měsíci +46

    Don't be afraid of gotos. At the core, the goto statement represents one of the most fundamental building blocks of computing; the jump. Without jumps there would not be touring completeness. I love the fact that C allows you to directly use these very low level bricks, as you can implement control flows that are impossible with ifs, switches, whiles and for loops. Once again, C gets you closer to your hardware and that's a feature, not a bug.

    • @lukekurlandski7653
      @lukekurlandski7653 Před 6 měsíci +8

      All you need for Turing completeness is if-statement and while loop (both if these use goto under the hood). In a small number of scenarios, goto might make your control flow simpler, but you can always achieve the same thing without it.

    • @sivorano
      @sivorano Před 6 měsíci

      ​@@lukekurlandski7653I think you also need either goto or recursion for turing completness.

    • @LogicEu
      @LogicEu Před 6 měsíci +5

      ​@@lukekurlandski7653 Yes! That's almost right! You don't actually need while loops, just if-statement and goto-statement actually. In languages like BASIC you don't get a built in loop statement, you just use ifs and gotos to go back en repeat the loop until a variable reaches a certain value. I kind of like that because it reflects how your computer actually execute your loops under the hood.

    • @roberthickman4092
      @roberthickman4092 Před 6 měsíci +4

      Its stupid that wasm was designed without a jump.

    • @Zooiest
      @Zooiest Před 6 měsíci

      ​@@roberthickman4092 br and br_if

  • @mb00001
    @mb00001 Před 6 měsíci

    i kind of predicted what you were going to do only i was thinking of a switch statement, which in retrospect won't work because the jumps are for different conditions

  • @hellNo116
    @hellNo116 Před 4 měsíci

    the way i have experienced is that we tell it to newbies because newbies don't know how to write code and we don't want them to use it because they will be confused and write worse code. i have seen this live many times, while helping in uni.

  • @SegFaultMatt
    @SegFaultMatt Před 6 měsíci +1

    It’s nice to have “finally” in higher level languages 😅

  • @nmmm2000
    @nmmm2000 Před 6 měsíci

    I agree. also goto is good for break from 2 or more cycles at once.

  • @eagold
    @eagold Před 3 měsíci

    sometimes, based on some expression in the nested loop, you need to break nested and parent loop
    i still don't know how to do that without goto

  • @efemboygg
    @efemboygg Před 3 měsíci

    gotos are how i first learned to code. needed for use in my 1k line ti-84 scripts, and used them in .bat files i created in school too

  • @TheJaguar1983
    @TheJaguar1983 Před 5 měsíci

    I would probably nest these in inlined functions instead of using GOTO. Though, that could get rather cumbersome if you have a lot of things to close or free. I think the no GOTO thing is due to overuse and/or interfering with higher level language elements like unwinding and reference counting.

  • @L4ller0
    @L4ller0 Před 6 měsíci

    Hello! First of all, I wanted to thank you for your great videos which are always very educational.
    I have a question:
    Let's assume a context where 2 processes running simultaneously handle the "server.config" file. One of them could be the process you explained (which we will call process1) while the other (which we will call process2) is a process that can also delete the file.
    What if the scheduler after performing the check operation on the correct return value of the system call "open" in process1 passes control to process2 which deletes the file?
    Is there an atomic open and check for the file descriptor?
    I hope I have been clear enough!
    Thank you very much

    • @raptoress6131
      @raptoress6131 Před 6 měsíci +1

      Sounds like a mutex would do the job

    • @L4ller0
      @L4ller0 Před 6 měsíci

      @@raptoress6131 Thank you, but is there in your opinion something like "compare_and_swap"?

    • @jbird4478
      @jbird4478 Před 6 měsíci +2

      Nothing will happen, because the file doesn't actually get deleted until all open file handles are closed. So process1 will behave as if the file still exists, because its file handle was created first. If you want it to be otherwise, you'd need to implement some form of synchronization between those processes yourself.

  • @roadrunner3563
    @roadrunner3563 Před 6 měsíci

    depends on how well the language handles error conditions. sometimes there's no better way.

  • @emmettdja
    @emmettdja Před 4 měsíci

    I use goto whenever I have user input validation. Imo it is cleaner than using a while loop to ask the user to re-enter their input.

  • @realdragon
    @realdragon Před 5 měsíci

    So basically if you have 1 list to go through in functions but each function starts at different point then you use go to. When function_1 starts on top of the list and goes trough every element but function_2 starts in the middle of the list we don't want to copy paste half of the list, we just say program to go to that half point of list we defined defined only once

  • @BobFrTube
    @BobFrTube Před 6 měsíci +3

    The point I made a half century OK, (OK, more than) is that you want to reading the static state of the code to give you an understanding of the dynamic state. Unrestrained gotos make this difficult. This is why we use words like "try/finally", "break", "continue" etc. to indicate that are doing constrained flows and thus our reading of the static code is consistent with the dynamic flow.
    If you're using an ancient language and need to use GOTO, then annotate the usage to give the reader (and yourself) and even break (pun?) in understanding what is going on.

  • @davidadesina3321
    @davidadesina3321 Před 5 měsíci

    Yo I've got a question
    If hyper v is bare metal then I should be able to boot straight to say Kali right? If that's true can you show how

  • @zxuiji
    @zxuiji Před 4 měsíci

    you could further simplify that code with a macro:
    #define ERRTHENGOTO( RETVAL, LABEL, MSG ) { retval = RETVAL; perror(MSG); goto LABEL; }
    ...
    if ( cond )
    ERRTHENGOTO( -1, cleanup_x, "failed y" )
    Sure the lack of semicolon makes it look a bit wrong but the all caps name helps indicate it's a macro and shouldn't be worried about the look of it.

  • @stickfigure31
    @stickfigure31 Před 6 měsíci

    I haven't used goto statements in C before. This intrigues me, but having started with languages like Atari BASIC where jmp or goto statements were required to do any loops. I never related to the hate for goto statements as the following is perfectly readable to me and seems more intuitive for learning about computers then what modern languages tend to do
    10 print "Hello world!"
    20 goto 10
    or to break after so many cycles
    10 x = 0
    20 print "Hello world!"
    30 x = x + 1
    40 if x = 10 then goto 60
    50 goto 20
    60 ...
    Though I do appreciate the ability to break thing down into separate functions/libraries in C

  • @richardfarrer5616
    @richardfarrer5616 Před 5 měsíci

    So, since you mention switch (evil grin).
    retval = 0;
    if(error1)
    {
    retval = 1;
    goto oops;
    }
    dostuff1();
    if(error2)
    {
    retval = 2;
    goto oops;
    }
    dostuff2();
    ...
    if(errorn)
    {
    retval = n;
    goto oops;
    }
    dostuffn();
    do_more_stuff();
    oops:
    switch(retval)
    {
    case n:
    tidyn();
    case n-1:
    tidyn_1()
    ...
    case 1:
    tidy1();
    case 0:
    return retval;
    }
    What could be clearer than (ab)using the fallthrough mechanic?

  • @stapler942
    @stapler942 Před 6 měsíci +5

    One thing I still find hilarious is that Java has goto as a reserved keyword just so nobody can use it. 😆

    • @xwtek3505
      @xwtek3505 Před měsícem

      I heard that goto keyword is used internally in javac

    • @sub-harmonik
      @sub-harmonik Před měsícem

      but it's true that the labelled-block-break mechanism of java can almost always do the same thing, and sometimes it's clearer to have the 'section that can be jumped out of' in a block like that.

  • @rhone733
    @rhone733 Před 6 měsíci +1

    Gotos are fine when used properly. I only use them inside of functions to jump to a cleanup or error case.

    • @vibaj16
      @vibaj16 Před 3 dny

      The main use I have for goto is breaking out of nested loops. Yes, it's possible to do it without goto, but most methods for that make the code less readable to me. People only really do that for the sake of not using goto.

  • @assimilater-quicktips
    @assimilater-quicktips Před 5 měsíci

    The biggest problem to my knowledge with goto is the potential to mess up the stack. It’s generally just safer to build off the stack with a series of function calls than create a state where the call stack is uncertain

  • @Humanrebel
    @Humanrebel Před 4 měsíci

    Some of the cide duplicated you can get rid of by inverting the conditions. I'd prefer some more indentations rather than goto.

  • @MrEthanhines
    @MrEthanhines Před 3 měsíci

    In the 80’s I programmed in Basic for the C64 and there were *tons* of Gotos hence why i found it strange why they have fallen out of favor.

  • @Alibaba-id4dw
    @Alibaba-id4dw Před 6 měsíci +1

    One thing that annoyed me in some variants of C, is that, some compilers do not let you goto over a variable declaration. Even if no code after the jump ever used said variable. I think newer variants of visual studio act like that, while older ones allowed it.

    • @atijohn8135
      @atijohn8135 Před 6 měsíci

      can't you just put the variable in a scope?
      e.g.
      ```
      goto label;
      {
      int var;
      /* ... */
      }
      label:
      ```

    • @Alibaba-id4dw
      @Alibaba-id4dw Před 6 měsíci

      ​@@atijohn8135 this works, but it ugly, I have to declare "output" variable before I enter such subscope. Python has a del keyword that can actually "remove" local variables, but I don't see many people use that.
      Also I can just declare all local variables at the start of the function, like in ye olde C, which is what I ended up doing for the function that used goto. But maybe whining here can make somebody change something.

    • @Alibaba-id4dw
      @Alibaba-id4dw Před 5 měsíci

      @@RPG_Guy-fx8ns Why are you telling me all this? Everything works with global variables, but working with local variables and goto in C got somewhat annoying recently.

  • @bobobo1673
    @bobobo1673 Před 6 měsíci +1

    A teacher told me that if I used "goto", he would make me fail all the exams I took where I used "goto" and that that sentence should never be used

  • @SaSo-mk6yh
    @SaSo-mk6yh Před 6 měsíci +2

    My teacher always got visibly upset when anyone used gotos 😂

  • @acf2802
    @acf2802 Před měsícem +3

    Some asshole wrote a paper titled "goto considered harmful" and 56 years later idiots are misinterpreting it having only every heard the title and not the body and taking it as a universal law completely removed from it's original context. The paper was written in a time where FUNCTIONS were considered some confusing new-fangled invention by many programmers. The goal of the paper was to convince people that you should use higher level abstractions like functions. If you as a programmer in 2024 use functions (YOU DO) then you can COMPLETELY DISREGUARD "GOTO considered harmful" because IT'S NOT FOR YOU!

    • @DinHamburg
      @DinHamburg Před 19 dny

      back in the day FORTAN was widely used - and it had 'computed goto' and 'arithmetic if' which could easily create messy code which is nowadays completey inconceivable

  • @steelcock
    @steelcock Před 6 měsíci

    thanks my boiiiii

  • @powertomato
    @powertomato Před 3 měsíci

    An exception in C++ is basically a goto chain. Everywhere, where throwing an exception in a higher language would be appropriate I consider a valid use of goto. Something resembling try-catch-finally would be an unreadable mess in C without goto

  • @lovalmidas
    @lovalmidas Před 3 měsíci

    Interesting. I would like to hear about alternatives to GOTO / JMP in assembly. :D

  • @soulty3878
    @soulty3878 Před 6 měsíci

    When I need to multi-break from multiple loops in one condition I use goto. Sometimes it's just *both* faster and more readable

  • @yapdog
    @yapdog Před 6 měsíci +1

    *_Eff that!_* I've been using gotos in C for over 3 decades, and I have no intention of removing them. I use goto in virtually every function in my OS. I use them for error value reporting, jumping to the bottom of the function, thus having only 1 goto error exit point (e.g. "error_exit") and 1 success exit point (e.g. "success_exit") for every single function while having a much more descriptive error log.
    So, I would even modify your code example by only having the error gotos log the error then goto "error_exit" where the error return value is set. And since the cleanup may need to be performed regardless of success or failure along the way, "error_exit" then goes to "success_exit" where said cleanup is handled. Without having to check error logic, this is clean and consistent, becoming second nature when you write functions.