Visualization of every goto statement in the Linux 6.17 source code.Commentary from a 2003 linux-kernel mailing list discussion about the use of goto.Created...
Option 1 is really the only reasonable option for large enough codebases.
Option 2 is bad because duplicate code means you might change the cleanup in one code path but not some other. Also duplicate code takes up too much valuable screen space.
Option 3 has a runtime cost. It has double the amount of conditionals per error point. It also adds one level of indentation per error point.
Option 4 is same as option 2 but you edit all error paths in one single place. However, this comes at the cost of having to write 2 functions instead of 1 for every function that can error. And you can still mess up and return while forgetting to call the cleanup function.
You must also consider that erroring functions are contagious, just like async ones. I’d say most of the time a function is propagated upwards, with very few being handled just as it ocurrs. This means that whichever downside your option has, you’ll have to deal with it in the whole call stack.
Not really. There are quite a few of structures you can make with gotos that can’t directly be translated into functions. Sure, you can implement any functionality in any programming paradigm, but it might require much more work than to just replace goto with a function call.
Go-To’s are just a primitive functions that dont isolate code, just use functions.
In C, goto is basically a necessity though. There is really no good way of error handling.
Options:
void func(void *var) { void * var2 = malloc(); if var == Null { goto err; } do_something(); err: free(var2); }
void func(void *var) { void * var2 = malloc(); if var == Null { free(var2); return; } do_something(); free(var2); }
void func(void *var) { bool error = false; void * var2 = malloc(); if var == Null { error = true; } if !error { do_domething() } free(var2); }
void cleanup(void *var2) { free(var2); } void func(void *var) { void * var2 = malloc(); if var == Null { cleanup(var2); return; } cleanup(var2); }
Option 1 is really the only reasonable option for large enough codebases.
Option 2 is bad because duplicate code means you might change the cleanup in one code path but not some other. Also duplicate code takes up too much valuable screen space.
Option 3 has a runtime cost. It has double the amount of conditionals per error point. It also adds one level of indentation per error point.
Option 4 is same as option 2 but you edit all error paths in one single place. However, this comes at the cost of having to write 2 functions instead of 1 for every function that can error. And you can still mess up and return while forgetting to call the cleanup function.
You must also consider that erroring functions are contagious, just like async ones. I’d say most of the time a function is propagated upwards, with very few being handled just as it ocurrs. This means that whichever downside your option has, you’ll have to deal with it in the whole call stack.
Not really. There are quite a few of structures you can make with gotos that can’t directly be translated into functions. Sure, you can implement any functionality in any programming paradigm, but it might require much more work than to just replace goto with a function call.