Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Goto is considered useful by the book:

The use of goto and similar jumps in programming languages has been subject to intensive debate, starting from an article by Dijkstra [1968]. Still today you will find people that seriously object code as it is given here, but let us try to be pragmatic about that: code with or without goto can be ugly and hard to follow.



I've found goto to be a good way of dealing with exceptions in low-level C. For example:

    void* foo() {
        int handle = get_some_handle();
        if (handle < 0) {
             goto fail;
        }

        void* something = some_function(handle);
        if (something == NULL) {
            goto free_handle;
        }

        void* something_else = some_other_function(something);
        if (something_else == NULL) {
            goto free_something;
        }

        return something_else;

    free_something:
        free_something(something);
    
    free_handle:
        free_handle(handle);

    fail:
        return NULL;
    }
I've seen this pattern frequently in the Linux source code. I think this is an example of a case where usage of goto improves readability and reduces errors.


Yes - a thousand times yes!

The goto has gotten a bad rap over the years because of Dijkstra's paper. And that paper has unduly influenced a lot of incorrect thinking. There are valid use cases for goto, and this is certainly one of them.

I use it all the time like the example above. Particularly because it makes my life so much easier when developing and debugging embedded C code across various tool chains, some of which have less functionality than others.

[edit - correct typo on Ed's name]


Just curious, not a C developer by any means, but why wouldn't you use a function here instead of a goto? I'm confused how goto would reduce error/improve readability in that example.

Again, not criticizing, genuinely want to know.


Simply: a goto never returns while a function call returns to where it was called from.

So specifically in the example above, if you called failure-handling functions instead of using goto's then when the function returned you would continue execution on the next line after the function call. In the example above, that's clearly not what you want.

Now you could add some else's after the function calls to prevent execution from continuing. i.e. to get to the appropriate step in the free_* sequence at the bottom, but that starts to look messy. So I have to admit (not being a goto-lover), the above example reads very nicely.

It conforms to the "gotos might be okay if they only jump forward" rule of thumb I've heard.


I've also seen extensive use of gotos for exception handling in C. After the knee-jerk reaction ("...but but Dijkstra!") I came to appreciate it as a useful idiom.


To be fair, Dijkstra said "harmful", not "forbidden". He was also talking about encouraging structured procedural programming rather than a game of Who's Clever Enough to Follow the Spaghetti.

We do things that are harmful all the time, in limited appropriate situations. Cutting into your abdomen is harmful, but a skillfully used surgeon's scalpel can fix a bigger problem. That's not license to go roll around on a pile of jagged, rusty steel scrap. Missing sleep is harmful, but if you do it once in a while to keep your job or to escape a nighttime flash flood then it's helpful.

Dijkstra was intending to set the norm from which people should mindfully and occasionally deviate. The point wasn't to ban the use of labelled jumps entirely.


GKH somewhere explained that they accept gotos that don't go back (leads to mess) only gotos that jump forward in function. Nice rule.


This looks fine to me. I wonder if C/C++ could be improved by introducing a new keyword `bail` which is the same as `goto` but is only allowed to jump to the bottom of the function. That way, codebases can outlaw `goto` but keep `bail`.


Are you looking for "return"?

With C++ you can ensure that you have your destructors do the tidy up, e.g. a messy example

struct cleaner { cleaner(string *toCleanup) : m_x(toCleanup) { } ~cleaner() { delete m_x; m_x = nullptr; } };


Yup, C++ has autocleanup. Of course if you are using fopen() instead something more modern you'll need to fclose(). Adding a new keywords to C is a long shot. Perhaps compilers could detect non-cleanup use of goto and give it a warning.


A typical C++ codebase I'm working on these days would have scope guards implemented via macros, such that you can do e.g.:

    FILE* f = fopen(...);
    SCOPE_GUARD({ fclose(f); });
This is mainly used for one-off calls to some native API, where writing a proper RAII wrapper for the managed resource is not worth it.


In a previous job where I wrote C code, I had a macro named "bail" that pretty much did that: log an error message, then jump to the cleanup section of the function.


Wouldn't it be better to have some sort of linter tool do this? Why create a more specific language construct when you already have one?


I'd much rather see that as a state machine.


How common is it to add "exception macros"? Something like:

"error(handle, "could not open handle", free_something)"


Have you ever used goto in C? I feel like most people bash on C just because they heard Dijkstra said it, and that's it.

Most code I saw while teaching it were not good cases, but sometimes it's a very interesting technique that can make the code easier to understand and shorter. I think that use is beautiful.

But it doesn't mean there aren't bad use cases.


I think you meant "bash on goto" instead of "bash on C"?

Regardless, yes, a ton of people do bash on it because of Dijkstra - but at the time, he had a good point. In the industry of the time (as I understand it - I was a kid when he wrote that), there was a lot of "cowboy coding" out there, with goto's "gone wild" - jumping into the middle of everywhere and everything - and producing "spaghetti code".

But as you note, it can be very useful and make things easier to read (for instance, jumping out of deeply nested if-then constructs - though I could also argue a refactor might be the better solution).

I was once part of a discussion in a forum about state machines, and one guy posted a very beautifully done state machine that used no select-case construct, but rather goto statements, but done in a tight way that mimic'ed a select-case construct. I was very impressed at the time; it was some code for PIC Basic IIRC.

In time, I've changed my views from seeing goto as "always bad", to "can be very useful, in some situations - provided you know the risks of the tool".

In other words - think very carefully before you rush into using it; maybe there's a better or cleaner way.


The only valid use of goto I've seen is for breaking out of nested loops; a goto statement is much easier than unwinding a bunch of breaks based on arbitrary logic or flags to notify each parent loop that a break is needed.


It's also handy for error handling / cleanup: http://eli.thegreenplace.net/2009/04/27/using-goto-for-error...


The main argument against goto comes from standard C++ side because there are so many edge cases where goto and longjmp will cause your exceptions and end-of-life semantics to go awry.


If I remember correctly, C++ flat out bans all uses of goto that could affect constructors and destructors. For example, something like this won't compile:

    int main() {
        goto g;
        std::string s;
        g: return 0;
    }
while this will compile, but destructor is guaranteed to be called:

    int main() {
        {
            std::string s;
            goto g;
            return 1;
        }
        g: return 0;
    }
Now, longjmp is another matter. That thing is basically verboten in any sane C++ environment (and consequently, C libraries that use it across API boundary are very painful to use from C++; R hosting API is a great example of that).


It's been brought up that there are a few handy uses for goto. I think the reason it's so heavily preached against is because of its name. For someone just starting out, the word "goto" might sound like a handy tool that could be useful for all sorts of things.

But instead of a measured response to make it the last tool you reach for, it's been made into a pariah.


It's only more useful than structured code in a few niche situations, and even then, it doesn't usually provide massive benefits. It's a language construct that doesn't carry its weight.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: