| Funny how my Python code doesn't have those arrow issues. In C code, I understand some standard idioms, but I haven't really ever seen a goto I liked. (Those few people who are trying to outsmart the compiler would make a better impression on me by just showing the assembly.) IMX, people mainly defend goto in C because of memory management and other forms of resource-acquisition/cleanup problems. But really it comes across to me that they just don't want to pay more function-call overhead (risk the compiler not inlining things). Otherwise you can easily have patterns like: int get_resources_and_do_thing() {
RESOURCE_A* a = acquire_a();
int result = a ? get_other_resource_and_do_thing(a) : -1;
cleanup_a(a);
return result;
}
int get_other_resource_and_do_thing(RESOURCE_A* a) {
RESOURCE_B* b = acquire_b();
int result = b ? do_thing_with(a, b) : -2;
cleanup_b(b);
return result;
}
(I prefer for handling NULL to be the cleanup function's responsibility, as with `free()`.)Maybe sometimes you'd inline the two acquisitions; since all the business logic is elsewhere (in `do_thing_with`), the cleanup stuff is simple enough that you don't really benefit from using `goto` to express it. In the really interesting cases, `do_thing_with` could be a passed-in function pointer: int get_resources_and_do(int(*thing_to_do)(RESOURCE_A*, RESOURCE_B*)) {
RESOURCE_A* a;
RESOURCE_B* b;
int result;
a = acquire_a();
if (!a) return -1;
b = acquire_b();
if (!b) { cleanup_a(a); return -2; }
result = thing_to_do(a, b);
cleanup_b(b); cleanup_a(a);
return result;
}
And then you only write that pattern once for all the functions that need the resources.Of course, this is a contrived example, but the common uses I've seen do seem to be fairly similar. Yeah, people sometimes don't like this kind of pattern because `cleanup_a` appears twice — so don't go crazy with it. But I really think that `result = 2; goto a_cleanup;` (and introducing that label) is not better than `cleanup_a(a); return 2;`. Only at three or four steps of resource acquisition does that really save any effort, and that's a code smell anyway. (And, of course, in C++ you get all the nice RAII idioms instead.) |
this rings alarm bells for me reading that a cleanup_c(c) has maybe been forgotten somewhere, since the happy and unhappy paths clean up different amounts of things.
i imagine your python code escapes the giant tree by using exceptions though? that skips it by renaming and restructuring the goto, rather than leaving out the ability to jump to a common error handling spot