Live data from Hacker News

GOTOphobia considered harmful in C

blog.joren.ga

31–40 of 319 posts

Re: GOTOphobia considered harmful in C

#31

The C version: int* foo(int bar) { int* return_value = NULL; if (!do_something(bar)) goto error_1; if (!init_stuff(bar)) goto error_2; if (!prepare_stuff(bar)) goto error_3; return_value = do_the_thing(bar); error_3: cleanup_3(); error_2: cleanup_2(); error_1: cleanup_1(); return return_value; } The D version: int* foo(int bar) { scope(exit) cleanup1(); if (!do_something(bar)) return null; scope(exit) cleanup2(); if…

Do scopes work without linking against the D runtime?

Re: GOTOphobia considered harmful in C

#32

In RAII languages[0], you obviously don't need unrestricted gotos. However, I always find myself missing it when writing nested loops. Labeled break and continue[1] ought to be considered standard structure programming primitives. These are restricted gotos and allowing them to break or continue a parent loop doesn't unrestrict them much. But it does significantly improve the expressive power of your looping construc…

This is one of those half-true claims that C++ aficionados make, probably because they can play a bit fast and loose with resource cleanup in their particular situations.

RAII simplifies some of the resource cleanup, but at a cost: if the resource cleanup fails, there’s essentially no way to convey this.

So yes, you can write a destructor that tries to clean up your resources regardless of how the code exits its current scope. But if that cleanup encounters a problem, the destructor can, at best, try to convey this indirectly, either by (commonly) logging or (rarely) setting a variable to a value. It certainly cannot throw another exception, or even directly manipulate the return value of the function.

This is fine for some purposes, and completely unacceptable for others. But it’s not equivalent to the explicit cleanup and error handling in C.

So some of us occasionally find ourselves in an RAII language and using goto.

Re: GOTOphobia considered harmful in C

#33

In RAII languages[0], you obviously don't need unrestricted gotos. However, I always find myself missing it when writing nested loops. Labeled break and continue[1] ought to be considered standard structure programming primitives. These are restricted gotos and allowing them to break or continue a parent loop doesn't unrestrict them much. But it does significantly improve the expressive power of your looping construc…

This is one of those half-true claims that C++ aficionados make, probably because they can play a bit fast and loose with resource cleanup in their particular situations. RAII simplifies some of the resource cleanup, but at a cost: if the resource cleanup fails, there’s essentially no way to convey this. So yes, you can write a destructor that tries to clean up your resources regardless of how the code exits its curr…

You can totally throw an exception from RAII code if you declare the destructor noexcept(false).

Goto + RAII isn’t generally compatible unless you structure things very carefully

Re: GOTOphobia considered harmful in C

#35
This is fun! The C version;

    int foo(int v) {
        // ...
        int something = 0;
        switch (v) {
            case FIRST_CASE:  something = 2; goto common1;
            case SECOND_CASE: something = 7; goto common1;
            case THIRD_CASE:  something = 9; goto common1;
            common1:
                /* code common to FIRST, SECOND and THIRD cases */
                break;

            case FOURTH_CASE: something = 10; goto common2;
            case FIFTH_CASE:  something = 42; goto common2;
            common2:
                /* code common to FOURTH and FIFTH cases */
                break;
        }
    }
The D version:

    int foo(int v) {
        // ...
        int something = 0;

        void common1() {
                /* code common to FIRST, SECOND and THIRD cases */
        }

        void common2() {
                /* code common to FOURTH and FIFTH cases */
        }

        switch (v) {
            case FIRST_CASE:  something = 2;  common1(); break;
            case SECOND_CASE: something = 7;  common1(); break;
            case THIRD_CASE:  something = 9;  common1(); break;
            case FOURTH_CASE: something = 10; common2(); break;
            case FIFTH_CASE:  something = 42; common2(); break;
            default: break;
        }
    }
Note the use of nested functions to factor out common code. The nested functions usually get inlined by the compiler, so there is no cost to them. Nested functions are a great way to eliminate gotos without penalty.

Re: GOTOphobia considered harmful in C

#36

The C version: int* foo(int bar) { int* return_value = NULL; if (!do_something(bar)) goto error_1; if (!init_stuff(bar)) goto error_2; if (!prepare_stuff(bar)) goto error_3; return_value = do_the_thing(bar); error_3: cleanup_3(); error_2: cleanup_2(); error_1: cleanup_1(); return return_value; } The D version: int* foo(int bar) { scope(exit) cleanup1(); if (!do_something(bar)) return null; scope(exit) cleanup2(); if…

I find that after writing a lot of Go, manually having to defer/scope(exit) is a lot more error prone than just RAII destructors: it’s impossible to forget to defer the destructor.

Re: GOTOphobia considered harmful in C

#37

Earlier quoted context omitted.

This is one of those half-true claims that C++ aficionados make, probably because they can play a bit fast and loose with resource cleanup in their particular situations. RAII simplifies some of the resource cleanup, but at a cost: if the resource cleanup fails, there’s essentially no way to convey this. So yes, you can write a destructor that tries to clean up your resources regardless of how the code exits its curr…

You can totally throw an exception from RAII code if you declare the destructor noexcept(false). Goto + RAII isn’t generally compatible unless you structure things very carefully

You can, and your program will call std::terminate if there’s already an exception being processed. Not exactly desirable if you’re trying to write code that ensures careful resource cleanup.

Also why it’s widely regarded as _wrong_ to ever throw in a destructor.

Re: GOTOphobia considered harmful in C

#38
post #24

In RAII languages[0], you obviously don't need unrestricted gotos. However, I always find myself missing it when writing nested loops. Labeled break and continue[1] ought to be considered standard structure programming primitives. These are restricted gotos and allowing them to break or continue a parent loop doesn't unrestrict them much. But it does significantly improve the expressive power of your looping construc…

Go doesn't have RAII or destructors, it has defer.

Which definitely does weird things in a loop.

Re: GOTOphobia considered harmful in C

#39

This is fun! The C version; int foo(int v) { // ... int something = 0; switch (v) { case FIRST_CASE: something = 2; goto common1; case SECOND_CASE: something = 7; goto common1; case THIRD_CASE: something = 9; goto common1; common1: /* code common to FIRST, SECOND and THIRD cases */ break; case FOURTH_CASE: something = 10; goto common2; case FIFTH_CASE: something = 42; goto common2; common2: /* code common to FOURTH a…

Only some goto use cases.

Re: GOTOphobia considered harmful in C

#40
I agree that in C, the disciplined use of goto is the way to go, but the "ok so far" version could be better written:

    if (oksofar) {
        oksofar = something_done = do_something(bar);
    }
    if (oksofar) {
        oksofar = stuff_inited = init_stuff(bar);
    }
and so forth.
Post reply on HN