Live data from Hacker News

Avoid Else, Return Early (2013)

blog.timoxley.com

321–330 of 601 posts

Re: Avoid Else, Return Early (2013)

#321
post #63

This also works well with a C++ `defer` helper. #define CONCAT_LITERAL(x, y) x ## y #define CONCAT(x, y) CONCAT_LITERAL(x, y) template struct DeferWrapper { F f; DeferWrapper(F f) : f(f) {} ~DeferWrapper() { f(); } }; template DeferWrapper deferWrapper(F f) { return DeferWrapper (f); } #define defer(code) auto CONCAT(_defer_, __COUNTER__) = deferWrapper([&]() code) Example of usage: { Foo *foo; if (initializeFoo()) {…

Similar approach was discussed a few months ago:

https://news.ycombinator.com/item?id=15523286

Re: Avoid Else, Return Early (2013)

#322

Programmers 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…

Wrong. You need to exit before resource allocations :-). And in general if you allocate resources in most functions you're doing it wrong. Need global resource managers. Stack variables should only very rarely be resource owners.

Re: Avoid Else, Return Early (2013)

#323
post #297
post #186

Earlier quoted context omitted.

No, I do a git blame, and see all the relevant commit messages. If there's not 1 line of code from that commit remaining why is it relevant? If something looks weird still - I go back to the commit that created this part of code and git blame that. I don't remember a case where I had to do 2 steps like that. BTW we have a rule of putting JIRA ticket numbers in commits, that makes it even easier to find out. You can s…

>No, I do a git blame, and see all the relevant commit messages. sounds great until there's a refactor (including moving code around), then all the "comments" get buried.

It's a bit humorous that often the same people who insist the code should be enough documentation follow that up by clarifying that git, of course, supplies the rest.

So something entirely outside the codebase, which may or may not be available to the person who needs the information, and which may or may not need to be extensively searched through years of history to find the relevant commit message, which may or may not be sufficient to explain the code... is better than having a comment in the code.

Re: Avoid Else, Return Early (2013)

#324
post #186

Earlier quoted context omitted.

When you read through a part of your system that you've either never seen before or have forgotten how it works, do you also read all commit messages for all of that code? I'm asking because that's the only way I can imagine one can learn about the edge cases and surprising consequences in non-trivial systems if you have a rule about not using comments to explain them.

No, I do a git blame, and see all the relevant commit messages. If there's not 1 line of code from that commit remaining why is it relevant? If something looks weird still - I go back to the commit that created this part of code and git blame that. I don't remember a case where I had to do 2 steps like that. BTW we have a rule of putting JIRA ticket numbers in commits, that makes it even easier to find out. You can s…

Git blame is great. But having to look at all commit messages over, say, a few hundred lines of code just to know about standard pitfalls does not sound efficient. Edge cases are not just in the places where code is obviously doing something odd. Sometimes they hide in seemingly normal looking code - the kind of code you may not think it's worth diving into the commit history for.

Re: Avoid Else, Return Early (2013)

#325
Certainly is hard to read nested code, but returning earlier makes it harder because now our mind has to construct the execution path instead of reading it. What I usually do is writing the body in a new procedure. Dijkstra designed a language with no return statement with a very simple semantics made for proving the program behaves exactly as its specification mandates. Niklaus Wirth designed Oberon with no return statement. Currently I write Go code only using return at the end of the procedure, my code is easy to follow and has fewer errors than before https://en.wikipedia.org/wiki/Guarded_Command_Language https://www.inf.ethz.ch/personal/wirth/ProjectOberon/index.h...

Re: Avoid Else, Return Early (2013)

#326
post #106

Programmers 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…

> Same way braces go on the end of the method/class name to reduce LOC. Screw that. I've been writing code for 15 years, and Allman style braces make it so much easier to mentally parse code into blocks that they're worth every single LOC. I can't speak for anyone else but I'm not working on an 80x24 terminal anymore.

I don't work on an 80/24 terminal either, but I find that if there's too much text on the screen at a time, my eyes glaze over and don't read it all. So I work with larger fonts and use a terser style with a 40-line rule for functions that aren't switch statements.

Re: Avoid Else, Return Early (2013)

#327

Earlier quoted context omitted.

This is a reasonable suggestion since the code isn't too bad. std::unique_ptr > p(new Foo, [](Foo* p) { if (p) destroyFoo(p); }); // initialize Foo and set to NULL if failed It increases complexity a bit because you no longer have a simple pointer, and you can't allocate on the stack anymore (my example should have declared `Foo foo;` with `destroyFoo(&foo)`, sorry for typo.)

If you didn't want a pointer you could have just used something like: template struct FooWrapper { TFoo foo; const TDestr destroyFoo; template FooWrapper(Tinit initializeFoo, TDestr destroyFoo) : destroyFoo(destroyFoo) { foo = initializeFoo(); if (!foo) throw FooException(...); } ~FooWrapper() { destroyFoo(&foo); } } Although really that should have been part of the "Foo" class itself, but if you need to deal with ex…

Oh yes, I forgot to make it clear that `Foo` is a C struct from a C API. There are tens of thousands of such libraries.

An issue with your wrapper is that it is not generic enough and thus must be written for each Foo-like object. That could likely be fixed with more template arguments, but of course there are multiple ways to initialize C objects like

- `fooInitialize(Foo foo); // expects that foo is pre-allocated`

- `fooInitialize(Foo foo); // allocates and sets the Foo pointer. Annoying, but some libraries do this.`

- `Foo fooInitialize(...); // taking certain arguments`

A single `defer` wrapper allows you implement custom destruction behavior for each instance, which is useful if you want to set flags or log errors in the destruction process.

Re: Avoid Else, Return Early (2013)

#328
post #280
post #183

Earlier quoted context omitted.

I've also been coding 30 years. I have to use same line at work, and I use next line in my (very large) side projects. Honestly, I don't know what the difference is.

> (very large) side projects How big once you remove all the extra newlines?

LOL. This is the part of the Silicon Valley episode-bar-scene where the fight breaks out.

Thank god OC didn't mention "Just like you move from tabs to spaces."

Re: Avoid Else, Return Early (2013)

#329
post #93

Premature return considered harmful.

Certainly is hard to read nested code, but returning earlier makes it harder because now our mind has to construct the execution path instead of reading it. What I usually do is writing the body in a new procedure. Dijkstra designed a language with no return statement with a very simple semantics made for proving the program behaves exactly as its specification mandates. Niklaus Wirth designed Oberon with no return statement. Currently I write Go code only using return at the end of the procedure, my code is easy to follow and I have fewer errors than before https://en.wikipedia.org/wiki/Guarded_Command_Language https://www.inf.ethz.ch/personal/wirth/ProjectOberon/index.h...

Re: Avoid Else, Return Early (2013)

#330

Earlier quoted context omitted.

> 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…

Oh common. This might be true for a very specific type of codebase, but it isn't true for programming in general. If I'm coding a library of standard statistical functions I'm exiting early. If I'm coding a Rails webapp I'm exiting early. If I'm coding a shell script, even one used on tens of thousands of servers, I'm exiting early. The resource almost all programmers are managing is the resource of human time. Human…

Don't forget the human time to debug the code (especially the rare or only-happens-under-load issues, which can be related to resource exhaustion, among other things).

Also, some of your examples (like altering or reviewing code) can become easier and faster if resource management is a first-class citizen in your code base or language (i.e. is either more explicit in the code, and you know to look for it and manage it, or it is somehow taken care of automatically by your language, so you would have a hard time forgetting it, even if it is handled implicitly).

Post reply on HN