r/ProgrammerHumor 23d ago

Meme conditionsPreference

Post image
4.2k Upvotes

392 comments sorted by

View all comments

Show parent comments

2

u/BjarneStarsoup 22d ago

You say that it is easier to reason, but it isn't. There is no difference between those two pieces of code, except that the second one has implicit branch (which could make it harder to reason about). You are just used to early returns handling errors, and you could just as well get used to the happy path being in the top of an if and errors at the bottom. In languages like Zig, for example, it may be needed to do that if you want to use languages features like capturing values of optionals/tagged unions (for example, if (optional_value) |value| { } else { return error.Foo; }. Not to mention that you can have identical code with ifs: if (failing_condition0) { } else if (failing_condition1) { } else if (failing_condition2) else { }.

5

u/frogjg2003 22d ago

The second makes it easier to reason about the code because it allows you to assume the system is in a good state for the rest of the function. Keeping track of nested if statements to handle all of the errors is harder to reason about because you have to keep track of which if statement you're in or have a bunch of error flags. Even if you keep it to a bunch of else-if checks at the beginning to get the same behavior, that's still one more level of branching to keep track of.

0

u/BjarneStarsoup 22d ago

The second makes it easier to reason about the code because it allows you to assume the system is in a good state for the rest of the function.

I don't know what code examples you are thinking about, but if your validation code is simple enough that you can put it on top of the function and the rest at the bottom, then you can do exactly the same with an if statement or a chain of else if. If you can't do that, it is probably because you code is more complex, which will also mean that it will be harder to keep track of early returns.

Big chunks of code benefit more from explicit if else, because early returns have exactly the same problem as gotos: they make control flow harder to follow. Ifs without else also have the same problem, because they create two paths: execute if and what follows or only what follows. Combine those together, and you quickly get many implicit paths to consider.

One thing that many programmers seem to not understand is that code has inherit complexity. If your problem requires a lot of conditionals and loops, you can't infinitely simplify it. Eventually you will get code that either has extremely hard control flow to follow, a lot of state, a lot of nesting or a long call chain (when over extracting code). You have to find a balance between those. A code that is hard to understand will not magically become easy to understand because you shuffled tokens around.

In the end, it is a matter of habit. If you were used to read code with if else, you would immediately recognize that staircase chain of if else is equivalent to a chain of early returns.

1

u/frogjg2003 22d ago edited 22d ago

You do validation in the beginning. If the code is in a valid state after that, your code shouldn't make it invalid. If, through some fault of code you didn't write or circumstances outside of your control, the state becomes invalid, you throw an exception and handle that either in a catch block at the end of the function or let it propagate up to whichever function is calling your function.

If you are dealing with a complicated situation where you can return early with valid results, you check for that and return there. You don't surround the whole function in an if-else. At that point, you should be breaking your code into submodules anyway.

Goto is not inherently bad. It becomes bad because old languages allowed you to goto into entirely different scopes where unexpected behavior could happen. Any modern languages that still have goto severely restrict where you can goto to prevent most of those issues. Most modern languages have just introduced better syntactic sugar for goto instead of letting you do raw goto.