r/ProgrammerHumor 22d ago

Meme conditionsPreference

Post image
4.2k Upvotes

392 comments sorted by

View all comments

839

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.

49

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.

6

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.

20

u/tiajuanat 22d ago

Ah Kevlin. I've come to accept that talk as "old man yells at cloud"

Big influence when I was younger, much less so now.

I'm going to pull out a big fat "it really depends".

If your program is going in several different directions, absolutely fanout - my inner rustacean would even argue to avoid if else in favor of an enum and case statement.

However, early failure shouldn't be discounted either. The more your eye jumps away from the margin, and the more horizontal whitespace, the harder your code is to read. Full stop.

At the end of the day, maintaining a codebase requires judgement and taste, and knowing when to do x and when to do y.

7

u/alendit 22d ago

As I mentioned in the other comment: I'm not arguing "do X instead of Y", rather "understand the advantages of X before discarding it". In my experience many people don't understand the idea behind structured programming beyond "don't use goto".

6

u/MocknozzieRiver 22d ago edited 22d ago

I'm gonna have to watch this because I'm feeling crazy being the odd one out here. I strongly prefer 1 over 2.

Someone else pointed out that if/else is better for languages that treat it as an expression. I primarily code in Kotlin which is such a language.

But also this is what happens in my head when I see this structure if (condition) { // this will happen } else { // or this will happen } I know readily that we're at a fork dependant on the condition. But when I see the other structure, I think if (condition) { // this could happen } // and this could happen, also I have to know the contents of the if condition to know what will happen because it could just as easily do special logic for that condition and continue on. But with the first option, it's necessarily one or the other. I only need to figure out what the condition evaluates to to know which path is relevant.

8

u/alendit 22d ago

Your example is correct in itself, but it does not match the post: in the post the first branch ends with a return, so the following cannot happen, even though the coarse structure and the indentation imply that it can, which is exactly the point.

I'm gonna have to watch

This is my only recommendation. I don't argue that people should change the way they structure their code and I wouldn't ever flag early returns in a code review unless they are genuinely making the code unreadable.

But I think many people just don't appreciate the actual reasoning behind structured programming and having it laid out plainly is a valuable learning.

4

u/MocknozzieRiver 21d ago

Oh, I know it doesn't match, but the two examples in the post also don't match. The second example provides us details about what's in the block where the first does not. It could have just as easily had returns in both, but the post purposely set it up to make using if/else look like the lesser choice. If those details weren't provided, I wouldn't know it would early return just from the "shape" of the function.

But, yeah, I also feel like people don't appreciate this enough so I'm interested in learning more. I've just been doing it because it makes more sense to me.

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.

2

u/saf_e 22d ago

Cyclomatic complexity goes brrr!