Earlier quoted context omitted.
I am arguing this is worse, since it expresses the logic in a more convoluted way.
I would argue that it is by no means more convoluted. It is quite clear and concise. All of the following are equally readable: if (x > y) { return x; } else { return y; } if (x > y) { return x; } return y; return (x > y) ? x : y; The logic would be convoluted if you are going through extra hoops in order to write your logic like this, making the flow of the application unclear. For some things, an else branch ends u…
Avoid Else, Return Early (2013)
351–360 of 601 posts
Re: Avoid Else, Return Early (2013)
#352Earlier quoted context omitted.
Downside is, now your cleanup code is spilled all over the codebase. And where it's implemented it lacks often the necessary context (from the location of use). So, it's often wrong or incomplete, or suffers from the type-for-single-usage syndrome. Yes, RAII works for the casual std::vector, but it's not a maintainable solution for general resources.
It's right next to the create code, not 'spilled all over the codebase'. And if you really want different behavior on destruction (which is _really_ rare IMO), you can pass a destruction strategy at object construction. If you don't know how you want to destroy something when you construct it, you need to take a step back and reexamine your architecture.
Re: Avoid Else, Return Early (2013)
#353Earlier quoted context omitted.
Let's say we can see 30 lines on our screen and the average function takes 5 lines with OTBS. That means we can see 6 functions at once with OTBS and 5 with Allman. That makes a difference at least in my case.
Not being a pest here, but how often are you comparing more than 2 functions at a time? I can't say that I have ever dealt with code in over 20 years where I had to deal with more than 2 functions at once. Maybe I am mentally disabled, but I can only focus on one logical task at a time. Can other programmers multi-task their coding?
The less scrolling, tab management, and other context switching I have to do to look at those "2" functions, the easier it is on my memory.
Re: Avoid Else, Return Early (2013)
#354Sort of agree, but I don't think if (err) { handleError(err) return } and if (err) return handleError(err) are equally good. The second one doesn't really make it clear wether handleError returns a value and that value is intended to be returned.
If the return value is important: if (err) return void handleError(err) And in non-promise-based async JS, the return value is almost always lost/useless anyway so `return x` has no effect, might as well repurpose `return` for short-circuiting.
Re: Avoid Else, Return Early (2013)
#355Earlier quoted context omitted.
There is a ton of code that only exists because of issues elsewhere in the code . This is the opposite of brilliant code: these are the dirty patchworks, the hacks glueing the whole thing together. Yet often these hacks are necessary, at least until some bug is fixed elsewhere. Clear, self-documenting code is great but it can't capture that holistic insight into what the whole program is doing. It can't capture conte…
Completely agreed. Put another way: the sentiment that code documents itself is only possible in purely logical systems with no edge cases or surprising consequences. As an example, our code base has a comment which refers to our internal issue tracker which itself refers to this HN comment: https://news.ycombinator.com/item?id=9048947
I was secretly hoping you actually meant your own comment, creating a recursive loop. But a surprise John Nagle is even better
Re: Avoid Else, Return Early (2013)
#356This breaks down immediately because no matter how much is “handled” at the top, any one of the neatly-packed doSomething() and doMore() calls at the end can still fail and need handling. You can’t conveniently omit the mess that would be created for checking each of those. “Errors in top if” is good advice but every “else” may need its own (indented) top “if”. Indentation isn’t that nice but it is a very loud indica…
For the purposes of this post, it is assumed that any errors produced in those calls will automatically bubble up the stack to some caller or to the top level. In my experience, most JS code is not written with fine-grained error checking around every expression, if there's any explicit error handling at all. The example code isn't intentionally omitting any mess, rather it appears to me to be fairly typical.
The "handing" at the top is mainly for checking function preconditions. e.g. "does it even make sense to proceed?". Early returns help to decouple precondition checking from the important logic of the function, which IMO makes these types of checks easier to write and maintain and thus more likely to exist.
Re: Avoid Else, Return Early (2013)
#357Earlier quoted context omitted.
That link's favorite response actually refutes that brace style matters at all. No correlation with bug frequency detectable. So its all religion.
It's not "religion" if there's a technical reason to choose one method over another. A later comment on the SO post described how K&R can have maintenance costs because when moving things around it's more difficult to tell where a statement ends, and can accidentally cause side effects.
Re: Avoid Else, Return Early (2013)
#358Earlier quoted context omitted.
The irony is that Python actually has open-braces, but they're spelled ":" instead of "{". And the syntax effectively enforces K&R style. When I write Python I end every block with a "pass" statement so that emacs can auto-indent my code properly. The "pass" statement thus effectively becomes a close-brace. It drives Pythonistas into conniptions, but I never have to worry about reverse-engineering a block of code to…
That's the bad part of not having braces. If boundaries exist they need to be clear. One shouldn't have to count the tabs that make up the level of indentation. Its already a challenge reading code. Counting invisible tabs makes it even worse.
Re: Avoid Else, Return Early (2013)
#359Programmers with lots of hours of maintaining code eventually evolve to return early, sorting exit conditions at top and meat of the methods at the bottom. Same way you evolve out of one liners. Same way comments are extra weight that should only be in public or algorithm/need to know areas. Same way braces go on the end of the method/class name to reduce LOC. Same way you move on from heavy OO to dicts/lists. Same w…
> Programmers with lots of hours of maintaining code eventually evolve to return early, [..] I agree with all your other points and I‘d even agree if you wrote return early makes code more readable but not that it‘s something experienced programmers do. Programming is still - to some degree - resource management. Inexperienced devs often miss that fact, because they are focused on memory management and believe they c…
Even C has auto cleanup with __cleanup__ attribute in both gcc and clang.
Re: Avoid Else, Return Early (2013)
#360Earlier quoted context omitted.
Most languages with try/catch/finally don't have checked exceptions, so handling resource management in the those schemes is really brittle.
`finally`/RAII doesn’t depend on checked exceptions. It always runs (short of something that aborts the program without unwinding the call stack; and in those cases single-exit won’t save you).
And I'm not saying that finally depends on checked exceptions, I'm saying that pattern is very brittle. You change lower code to throw a new exception, and you change the above code to catch it like you're supposed to, but now the middle code has no idea that there's this new exception and leaks resources. So you end up either having brittle code who's correctness depends on implicit choices of the code around it, or you're wrapping pretty much all function bodies with try-catch-finally-rethrow.