Hacker News new | past | comments | ask | show | jobs | submit login

The “goto” style is better; it avoids excessive nesting and abusing “do { … } while (…)” for something wholly unrelated to looping. You want a jump, use a jump—it’s okay. “goto” lets you unwind from any number of errors without undue nesting or repetition:

    int foo(int bar) {

        if (!do_something(bar))
            goto do_something_error;

        if (!init_stuff(bar))
            goto init_stuff_error;

        if (!prepare_stuff(bar))
            goto prepare_stuff_error;

        return do_the_thing(bar);

    prepare_stuff_error:
        unprepare_stuff(bar);

    init_stuff_error:
        deinit_stuff(bar);

    do_something_error:
        undo_something(bar);

        return 0;

    }



Yup, jumps are the best way to correctly unwrap things (e.g. if you acquired resources), and if you're using it when you need to you might as well use it everywhere so your codebase is consistent.

Although I believe your jumps are in the wrong place logically speaking: if do_something() errored out, logically speaking you should not have to undo_something because do_something cleaned up its crap. So the jumps should be after the cleanups (and you should never need to unprepare_stuff).

Just as the opening of a file is not in a protected scope (if opening the file fails, you don't close it)


You’re right, you shouldn’t need to clean up after the first failure. I was thinking, say, new_a() succeeds and new_b() fails: you don’t need to free_b() but you definitely need to free_a(). The calling function is responsible for coordinating error handling amongst those functions it calls.

“…you should never need to unprepare_stuff”

I was just poking fun at the useless names.




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

Search: