6 ms·
> why return statements should be avoided in try-catch-finally blocks When I was a wee lad, learning basic and C, my father tried to impress upon me that a fun
by jwalton 5y ago
> why return statements should be avoided in try-catch-finally blocks
When I was a wee lad, learning basic and C, my father tried to impress upon me that a function should never have more than one `return` statement.
Back in those days, all these languages had `goto` statements, and we were told never to use them, because they were bad. But goto isn't bad because "goto" is a bad word - it makes your life unnecessarily complicated. A goto makes it very hard to reason about code, because you never know how you got to a certain line of code. Line 21 comes after line 20, but it might also come after line 30 if line 30 has a `goto 21`.
But, semantically, there's not a lot of difference between:
int myfunc(int *ptr) {
if (ptr == NULL) {
return 1;
}
return 0;
}
and:
int myfunc(int *ptr) {
int result;
if (ptr == NULL) {
result = 1;
goto END;
}
result = 0;
END:
return result;
}
When someone calls `myfunc`, and it returns, you don't know if it returned from the end of the function, or from the middle of the function. A function with multiple returns is a function full of gotos; or as my dad used to say: "Functions always have a single entry point; they should have a single exit point."
- RHSeeger 5y agoI've never been a fan of the "only one return" view. I find it far easier to understand when the "preconditions" are checked at the beginning of the function and, if they fail, bail out early (guard clauses). Then there's less mental load in the rest of the function.
- jwalton 5y agoI do this too. :P Especially in a language like Go or C where you don't have exceptions, I think the "fast fail" at the start of the function is a reasonable "exception to the rule". Otherwise you can quickly end up in a nested if statement hell. But back in the days when I was doing embedded work, I frequently came across problems where someone allocated some resource at the start of a function, freed the resource at the end of the function, but then either failed to realize there was a return in the middle of the function, or someone else came along later and added a return to the middle of the function; either way we ended up with a resource leak. I saw this pattern over and over again. "Fast fail" is reasonable design pattern, so long as it's at the top of the function and you're careful not to allocate things before you check for preconditions, but functions of the form: blah blah if blah blah return x else blah blah return y are (IMHO) an anti-pattern.
- Izkata 5y agoYeah, I'm pretty sure those leaks are the origin of it. At some point it became a "best practice" without understanding the reasons behind it, and people started applying it everywhere without any thought to "why".
- jonny_eh 5y agoThis has certainly become the the common best practice. I'm a fan too.
- twoodfin 5y agoI typically take this a step further, returning from trivial or common “fast-path” cases up front and falling through to any complex logic.
- deleted 5y ago[deleted]
- kilburn 5y ago> "Functions always have a single entry point; they should have a single exit point." Kind of moot as soon as you are using a language with exceptions, where by definition every function can have surprise exit points at every point where they call another function. Furthermore, the whole "goto is evil" ordeal has been debunked by the top professionals in our field [1] and discussed many times here on HN [2,3,4,5]. [1] https://koblents.com/Ches/Links/Month-Mar-2013/20-Using-Goto-in-Linux-Kernel-Code/ https://koblents.com/Ches/Links/Month-Mar-2013/20-Using-Goto... [2] https://news.ycombinator.com/item?id=18484221 https://news.ycombinator.com/item?id=18484221 [3] https://news.ycombinator.com/item?id=19959592 https://news.ycombinator.com/item?id=19959592 [4] https://news.ycombinator.com/item?id=14540088 https://news.ycombinator.com/item?id=14540088 [5] https://news.ycombinator.com/item?id=8760518 https://news.ycombinator.com/item?id=8760518
- aardvark179 5y agoI think it’s important to reflect on old practices and consider why they were important, and whether they still are. Many of the reasons for only having a single return were that it made it much easier to reliably clean up resources allocated by the function. Given a language with garbage collection, or even simply try, catch, and finally, provide a better way to handle this. The mistake Javascropt makes is allowing a return in a finally block.