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…
GOTOphobia considered harmful in C
31–40 of 319 posts
Re: GOTOphobia considered harmful in C
#32In 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…
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
#33In 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…
Goto + RAII isn’t generally compatible unless you structure things very carefully
Re: GOTOphobia considered harmful in C
#34Multiple COMEFROMs referencing the same label are an interesting way to effect multi-threading!
Re: GOTOphobia considered harmful in C
#35 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
#36The 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…
Re: GOTOphobia considered harmful in C
#37Earlier 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
Also why it’s widely regarded as _wrong_ to ever throw in a destructor.
Re: GOTOphobia considered harmful in C
#38In 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.
Re: GOTOphobia considered harmful in C
#39This 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…
Re: GOTOphobia considered harmful in C
#40 if (oksofar) {
oksofar = something_done = do_something(bar);
}
if (oksofar) {
oksofar = stuff_inited = init_stuff(bar);
}
and so forth.