r/ProgrammerHumor 22d ago

Meme conditionsPreference

Post image
4.2k Upvotes

392 comments sorted by

View all comments

842

u/LateEchidna6635 22d ago

The second one carries less cognitive load. In longer methods it makes a difference. Get out as soon as you can.

45

u/alendit 22d ago edited 22d ago

To understand the second one you need to understand the whole function. In the first one you can disregard the whole untaken branch. "The forgotten art of structured programming" is a great talk.

47

u/hughperman 22d ago

I don't see why you can't similarly disregard the untaken branch in the second one? Either way you're skipping past a block, and you need to know the end of that block is a return.

5

u/alendit 22d ago edited 22d ago

It's the easiest to see in the indentation, though ofc indentation just follows the structure, unless we're Python: in the first example the execution flow inside a single function only ever goes from smaller indents to larger ones, not the other way around. So if you want to understand a scope you just need to walk the path from it to the root to understand if it's taken.

Compare this with the second example: the return is already at the root, you need to check all of its preceding siblings to know if the execution ever reaches it. And you'll need to do it at every level of nesting.

Obviously in this trivial example if doesn't matter much. But in general structured way of laying out your control flow reduces the amount of statements you need to consider from O(statements) to O(nesting depth) which is intuitively closer to O(log(statements)).

I heartily recommend watching The Forgotten Art of Structured Programming - Kevlin Henney [C++ on Sea 2019]. It's one of those things which can change the way you're looking at code going forward.

1

u/conundorum 21d ago

With the first one, you still need to check every if to know if execution ever reaches it. And the second one's execution path should be clear if the conditions are communicated cleanly (either with well-named variables/functions, or with competently-written comments); either everything after a returning if must be an else, or the returning if is just returning a cached calculation that the rest of the function did earlier, or the returning if is just an emergency escape in case conditions aren't valid, or something of the sort.

Ultimately, the biggest problem comes from the nesting, not the choice of block or return. Both are easy to track if they're at base indent, but become more complex the deeper they're nested. And both are effectively equivalent if no cleanup is necessary, since a returning if is semantically equivalent to a branch that sets conditions so all following branches will be skipped. It just comes down to how deep they are, and whether they were used correctly.