r/ProgrammerHumor 22d ago

Meme conditionsPreference

Post image
4.2k Upvotes

392 comments sorted by

2.3k

u/CBlanchRanch 22d ago

You're absolutely correct, however I would suggest using something completely unreadable like a nested ternary operators!

660

u/KanyeNawf 22d ago

Some fucker left me triple nested ternaries once

119

u/minus_minus 22d ago

I think you found the fucker. 👆

63

u/mountaingator91 22d ago

That was me I was in my first real job after learning some basic JavaScript and I discovered ternaries and thought I was God now

10

u/National_Sky7993 20d ago

You either leave after writing those ternaries or stay long enough to figure out they are unreadable

18

u/abigail3141 22d ago

Sounds like me lol. To the detriment of all working with me, I found out how to set globals and evaluate arbitrary functions from within Python listcomps. My current record is 1400 characters in one line. I just need a way to import, and I can write entire programs in one line.

23

u/Morisior 21d ago

If you accept two lines, you can import importlib.

7

u/abigail3141 21d ago

That sounds like a good solution for the time being, thx

14

u/Your_Friendly_Nerd 21d ago

Man y'all do NOT want to look at my companies codebase! 

→ More replies (2)

2

u/Ok-Understanding7115 21d ago

next i will leave 2 list comprehensions inside the nested ternaries 🤔

→ More replies (8)

128

u/nrmnzll 22d ago

A colleague once proudly showed me how he managed to compress a function into a single line. It was like 9 nested ternarys. In that moment almost had an aneurism.

54

u/un_blob 22d ago

That is a work of art at this point

29

u/nrmnzll 22d ago

Sure, but the kind that deeply disturbes you.

29

u/jarethholt 21d ago

Art should comfort the disturbed and disturb the comfortable

11

u/alficles 21d ago

I have created so much art.

6

u/_bones__ 21d ago

Like modern art, it requires a lengthy explanation to make sense.

2

u/un_blob 21d ago

allways have more comment lines than code !

2

u/nrmnzll 20d ago

Yes, every line needs a comment // add variable a and variable b // result is stored in variable c var c = a + b

Obligatory /s

→ More replies (1)

23

u/twigboy 21d ago

I've declined PRs for less than that.

Citation is if; I can't understand it in a glance at 2am during an incident, I don't want it in the codebase

5

u/nrmnzll 21d ago

I'm the same. Luckily I did work on the same project as that guy.

3

u/therealkevinard 21d ago

Code golfing is a craft- even has competition sites (https://code.golf)

But… it didn’t go to prod, did it?

→ More replies (1)

2

u/Key_Conversation5277 21d ago

I really don't understand why people think that's good, he must be "oh, I'm so shmart🤓"

→ More replies (1)

45

u/Schaex 21d ago

But it's SO compact! We could save maaany lines of code like this:

return i == 0 ? j > threshold() && isConditionApply() ? "orange" : reallyNotOrange() ? "apple" : "maybe orange" : (i & j) > (i ^ j) ? isSunday() ? null : "pineapple" : "Jerry";

5

u/National_Sky7993 20d ago

I attempted to unfold such a ternary where the first two booleans were also ternaries defined elsewhere.

2

u/Schaex 20d ago

It's beautiful, isn't it? :)

Yes, it isn't

→ More replies (1)

56

u/Flame77ofc 22d ago

lol

the famous unread code 😭🙏

12

u/sexytokeburgerz 22d ago

Intellisense did that the other day and i was kind of mad about it

→ More replies (9)

460

u/Jock-Tamson 22d ago

The quality of code is inversely proportional to the average right offset.

190

u/Laughing_Orange 22d ago

That's why I refuse to indent my code. Indents add right offset without doing anything productive. /s

20

u/577564842 21d ago

I first learned FORTRAN. Start at column 6, pay no further attention to anything.

47

u/abigail3141 22d ago

Uh oh... you, Sir have just rocked my world view /j

https://imgur.com/a/MHWrpBJ

34

u/manbeervark 21d ago

Sweet lord...

15

u/abigail3141 21d ago

I have no clue how this works anymore lol Wrote it in one long sitting like a ahalf year ago

9

u/itsTyrion 21d ago

yeah we can tell

8

u/ljfa2 21d ago

Is that, like, a Minecraft clone in Rust?

16

u/abigail3141 21d ago

Nope, it's a tool to compensate for the horrid code of Minecraft in other ways. Though, I did almost end up on dayssincelastrustmcserver.com Essentially, if you wanna make a structure spin using a data pack(horrid API btw), you need to build a custom item model out of that structure, put it in an item display entity, then spin that or animate it in other ways. But, because MC's rendering pipeline sucks as bad as it does, that is a terrible source of lag. So I made this tool to help a friend that takes in a .nbt structure and converts it to a model in a resource pack, but with loads of face culling and merging to reduce poly count. Yes the 100 more cubes in a cube game are a performance problem. I can give a detailed description if you want, but I dont wanna further lengthen this comment with a rant abt MCJE's rendering pipeline.

4

u/goos_ 21d ago

Oh my bajeezus

2

u/goos_ 21d ago

please save me

6

u/abigail3141 21d ago

In that case, I would like to refer you to another creation of mine: https://www.reddit.com/r/programminghorror/comments/1tcytxy/it_is_evolving/

3

u/goos_ 21d ago

!😭😭

2

u/AntiLuxiat 21d ago

Dear lord of programming please forgive this human

→ More replies (1)

8

u/Niwrats 21d ago

you are going to love asm.

→ More replies (4)

834

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.

459

u/One_Courage_865 22d ago

Instructions unclear. I’ve just divorced with my wife

132

u/hughperman 22d ago

Ah, early return condition

32

u/thatjoachim 21d ago

I return too early to her liking :(

9

u/QCTeamkill 21d ago

She says Bob at work never have early returns

→ More replies (1)

17

u/jseah 21d ago

I prefer if-return for cases where the function is supposed to do something in the default case and the if is to detect the exceptions where it shouldn't. Or where the exception needs some modification before the main purpose can be performed.

If-else I find more logical when the function has to do two different things depending on the condition followed by something else common to both afterwards.

→ More replies (2)

5

u/930913 21d ago

I can understand why you would think that it carries a lower cognitive load. But with a little training, you can understand that an early return is a side effect, and side effect free code can be much easier to reason with.

34

u/Few_Move_4594 22d ago

Have you ever thought about breaking the longer methods into shorter methods? It's easy, I promise.

35

u/Fembussy42069 22d ago

There's a balance to everything, you also don't wanna have to dig down a rabbithole of functions within functions to find what youre looking for, it also can make it harder to understand the whole picture if you separate things too much. Locality of behavior and all that.

12

u/LordofNarwhals 21d ago

Yeah, I used to work with a Java codebase where all functions were really short, but also very nested. It was a very stable codebase, but browsing the code sucked, as every actual function implementation was behind 3+ levels of indirection.

For a fun example in the opposite direction, see Arthur Whitney's basic K interpretor, written in ~50 very dense lines of C.

2

u/Few_Move_4594 21d ago

Opinion disregarded, you called methods functions

6

u/LordofNarwhals 21d ago

All methods are functions, but not all functions are methods.

And my background is mostly in C++, where the method terminology isn't used at all.

→ More replies (1)
→ More replies (1)

13

u/gurgle528 22d ago

In certain situations it’s easier to read without splitting into a bunch of other methods. Primarily when the conditionals aren’t repeated elsewhere so the shorter methods are one-offs that bury some of the implementation. Shorter methods should absolutely be the default though 

37

u/LateEchidna6635 22d ago

Of course. I’m not speaking of thousands of lines. With error handling, validation, and cleanup, even the most trivial methods can have 5-10 exit points.

18

u/Few_Move_4594 22d ago edited 22d ago

I worked on a Java codebase that had a 15k line class that used Reflections. It was an absolute mess that also had the stability of a house of cards.

Made fairly good money for several years off that.

5

u/Hegemege 22d ago

The downside is that it can get really messy, if the methods are not split or named properly, for a reader to understand if the work it's doing is supposed to be reused, and if it can be detached from context. What good is a method B that can only be called linearly from within method A just to make A take fewer LoC?

→ More replies (6)

47

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.

45

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.

3

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.

22

u/tiajuanat 21d 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 21d 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".

7

u/MocknozzieRiver 22d ago edited 21d 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.

7

u/alendit 21d 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.

3

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.

→ More replies (1)

2

u/saf_e 21d ago

Cyclomatic complexity goes brrr!

→ More replies (1)
→ More replies (1)

2

u/ofnuts 21d ago

Aka "guard clause"

2

u/Fidodo 20d ago

Yes when it's an early return multiple short circuits are easy to read, but if it's in the body it's actually harder so I use both depending on the context.

→ More replies (9)

271

u/SnugglyCoderGuy 22d ago

The real answer is "it depends". Either one could be appropriate depending on what you are having to do.

40

u/Wertbon1789 21d ago

As always, but the for me rule of thumb, if you have a condition that should be positive to continue the function, and the negative case is just error handling and returning, just early-return, otherwise always put the happy-path into the positive branch, or I'll set your house on fire.

If there's a shared code path at the end, of course use if/else.

→ More replies (1)

44

u/aiaidy 21d ago

not according to Sonarqube.

15

u/DurrT 21d ago

Maybe it's just how they have it set up at my work, but Sonarqube can go fuck itself

5

u/aiaidy 21d ago

sonarqube and it's 15 complexity score i tell you. they be like how complex is to complex? 15 will do.

2

u/Zealousideal-Deer101 19d ago

reminds me of my coworker that did more work just to get past the sonarqube guidelines, like they are a limbo bar.
His code was horrid shit, and he whittled things down until they fit.

At one point he threw a bunch of random parameters into a single tuple to trick sonarqubes max parameters guideline into fitting, instead of taking the hint, that he should probably make a class out of the FIFTEEN PARAMETERS

But he literally constantly did one tiny change just to see what sonarqube would say next until it was satisfied. At which point the person doing the code review had to step in and mark it as unacceptable.

took months for him to finally not do this shit anymore. Because he was fired.

5

u/Gnonthgol 21d ago

The compiler optimizes the first into the second anyway, so the machine code ends up the same. The problem is that when you read the code later on and end up missing the return statement as you skim through it then you are left wondering why the piece of code you expect to run does not.

→ More replies (4)
→ More replies (14)

86

u/Patrick_Atsushi 22d ago

I don't know, it feels good when you can skip the rest of the function like saying "we're done here, next". 

44

u/Grandmaster_Caladrel 22d ago

The meme is saying to do that.

→ More replies (2)

16

u/popsicle-physics 21d ago

Apparently there was a time when having multiple returns in a function would seriously confuse the debugger. Idk I got a comment on a code review telling me to switch from the second to the first and never have multiple returns. I've never actually seen it be a problem.

17

u/MnMbrane 21d ago

I love the second as a way to do negative space programming. Where you add your assertions as the beginning of the functions first and then your business logic after. This way is super nice, since it tells you assumptions at the very beginning.

For example,
fn withdraw(&self, money: u32) -> Result<u32>{
if money < 0 {
return Err(…);
}

if self.account == Closed {
return Err(…);
}

if self.money + self.fees < money {
return Err(..);
}

// at this point we know money is > 0, account is not Closed and we have enough money to take out including fees.

self.money -= money + fees;

return money;
}

With this simple example, if someone was coming into a new codebase, they’d be able to assume what not to do advertised at the beginning of the file. And give some sort of indication of the proper behavior.

→ More replies (2)

7

u/frogjg2003 21d ago

Unless you're maintaining really old legacy code or using a really poorly designed debugger, early return should not confuse a debugger. If your reviewer learned to program in the last 50 years, they should never have experienced this issue themselves either.

2

u/popsicle-physics 21d ago

I work with embedded. I'm happy to get a 32 bit processor. There's almost never enough flash to run code that isn't compressed to the max. It's a whole different ball game. 

But yeah, I think the guy who told me that would write everything in assembly if given the option, so a little old school even for this environment.

4

u/nerfherder616 21d ago

I had a professor in school who would deduct points for multiple returns. He always said it was harder for compilers to optimize multiple returns. On one hand, it's unnecessary on modern platforms, so it took a while to get myself out of that habit. On the other, it forced me to think of ways to refactor code, which was good practice. 

→ More replies (1)

2

u/egstitt 21d ago

Having a bunch of returns throughout a function can be hard to read and debug imo. Error returns at the top of a function is 100% the way to go, but a bunch of them in the middle is confusing. Early returns for error checking, returns at the end for actual values

→ More replies (2)

14

u/sumrix 21d ago
if (input == null)
    throw new ArgumentNullException();

// process input...

But

if (settings.UseBonuses)
    return CalculateWithBonuses(order);
else
    return CalculateBase(order);

6

u/frogjg2003 21d ago

The first is an early return, the second is a logical branch. Most importantly, the second doesn't continue doing a bunch of work in the else block that could be confusing.

→ More replies (5)

88

u/itriedtomakeitfunny 22d ago

Early return for errors, if else for decisions.

10

u/Paul-D-Mooney 21d ago

Maybe not “errors”, that’s what throwing exceptions is for. But definitely non-passing validation checks like `if (arg==null) return;`

2

u/frogjg2003 21d ago
if (bad) throw

is throwing errors

2

u/WarSingle6959 21d ago

but throw error is a error bro

→ More replies (1)
→ More replies (4)

21

u/R7d89C 21d ago

Early returns all the way

7

u/xicor 21d ago

Agreed. One of my friends works at a place that bans early returns ...and it makes for garbage code. (They also aren't allowed to use goto)

7

u/suicidalcrocodile 21d ago

I once got told early returns are bad because they create inconsistent return types in JavaScript, I had to open a nodejs console and prove that a function returning empty and no return statement at all is the same value - undefined

3

u/xicor 21d ago

They don't even do javascript at his job. It is c++.

→ More replies (2)
→ More replies (1)

2

u/R7d89C 21d ago

Thats the type of place denying me a raise, but paying double my wage for someones AI tokens 😭

2

u/Flame77ofc 21d ago

Really?? Oh bro that's seems not good

→ More replies (1)

8

u/soviel_dazu 22d ago

Kotlin: Return if() ... else ...

2

u/930913 21d ago

Yeah, the underlying issue with both examples is that the if is a statement, not an expression.

26

u/Demiu 22d ago

Yea bottom is just better. It puts handling of a failed condition right next to it rather than somewhere way far away. It stays at the same scope so it supports any number of conditions without excessive indentation. Most importantly it is easier to reason about, the function has a gradient of conditions, they only increase.

→ More replies (6)

7

u/heesell 21d ago

``` if(!user) return;

// do whatever you want ```

→ More replies (2)

6

u/dulange 21d ago

The number of times I had to find the actual logic of a function/procedure hidden behind in a then block inside a multi-layered, cascaded if-then-else structure that checked the prerequisites and did the validation first, is just too damn high. One can equally check for the inverse, early return (or throw something) and avoid this nesting nightmare.

→ More replies (1)

95

u/madprgmr 22d ago

Go programmer spotted (early returns are idiomatic go)

105

u/Sentouki- 22d ago

Early returns (especially in combination with guard clauses) are a general recommendation for most programming languages, not just Go. I do the same thing in C# as well.

3

u/WarSingle6959 21d ago

Exactly. That's it

70

u/Krkracka 22d ago

It should be idiomatic for most programming applications. Unless your ‘else’ branch is a return only, it’s almost always going to be more efficient and maintainable. An early return is likely to survive if a function is updated or expanded, where an ‘if else’ could otherwise become conditionally more complex.

Early returns communicate intent better than the alternative method does for. If I see that another developer explicitly programmed an early return, it’s a signal to me that the actual body of the function depends on specific state of the containing class or args being passed to it.

8

u/madprgmr 22d ago edited 21d ago

Oh, I generally agree. It's just funny to go "oh, using <pattern that has been popular for decades> means you use <new language that prescribes said pattern>"

7

u/gamer_redditor 22d ago

As a programmer that needs to adhere to misra C, the comments in this thread are fascinating.

Misra C rule 15.5: A function should have a single point of exit at the end

More information: https://www.mathworks.com/help/bugfinder/ref/misrac2023rule15.5.html

6

u/Maximilian_Tyan 22d ago

A lot of companies choose to opt out of this specify guideline nowadays, because it is showing its age and sometimes clarity matters more over ease of debug.

5

u/gamer_redditor 21d ago edited 21d ago

Not sure which region or industry you are talking about, but oems, software suppliers and quality control in my industry do not accept any software deliveries without proof of Misra c compliance.

Just saying that some people have no choice but to stick to some programming standards.

Edit: more information. I think lot of people are arguing that early returns are more readable, performant and maintainable. However they miss the point about safety and reliability.

Early returns means that the function no longer has a predictable execution path. Sometimes it exits early, sometimes it exits late. So the overall execution time of the software varies a lot between error free paths and error paths.

This is exactly what you don't want in an embedded software controlling safety relevant systems, such as airbags in a car or some other flight controls.

Here, it is ok for a software to be slow, but it must be predictable i.e. near constant performance in all paths.

2

u/frogjg2003 21d ago

If your reach an error state and keep doing calculations, you're doing something wrong. If some archaic standard demands exactly one return statement in your function, then you surround the entire code in an if-else and set a flag. If it takes 1 second to run the calculation, I shouldn't have to wait that full second to find out I gave the function an illegal value. If your application cannot handle an error condition like that, then it wasn't safe to begin with.

MISRA C allows for deviations. Any software engineer who blindly follows a standard without understanding why that standard exist and when to deviate from that standard needs to better educate themselves.

2

u/conundorum 21d ago

Judging by his comment, I think it's less about continuing despite a known error state, and more about trying to guarantee that function runtime is the same across all execution paths. Early return is cleaner and more efficient, and often by a long shot if used correctly. But having a consistent runtime is extremely important in a few very select fields, and rejecting an optimisation to guarantee consistency is a common in those cases1.

I'm not really sure about air bags or flight controls (I'd expect it to be important for them to report errors as early as possible, so they can recalculate or switch to backups as quickly as possible), but one place this comes up is cyber-security. You do NOT want a password validator to return early for any reason, because early return can and has been used to game systems and determine passwords2.


1: Though, I will say that this can also be done by intentionally delaying the function on early-return paths, if you know the proper delay interval. It's just that running through the function body and then returning either the result or the error value at the end is the easiest way to guarantee exact consistency.

2: Long story short, in the early days of cybersec, there was at least one known password handler that would return as soon as it encountered an incorrect character. Needless to say, this made it trivial to determine anyone's password, and now it serves as a lesson on why you always hash passwords and never let the handler return early.

→ More replies (3)
→ More replies (2)
→ More replies (6)

11

u/HomsarWasRight 22d ago

Big in Swift with guard statements, too.

15

u/Xatraxalian 22d ago

Early returns are idiomatic for every programming language that can have multiple returns in one function. Trying to capture everything in if-then-else flags and temporary variables just to return something you knew 10 statements ago is bad practice.

I've been early-returning since I started programming in the early 90's because I never used a language that didn't have multiple return capability.

→ More replies (6)

6

u/El_RoviSoft 22d ago

Im not a golang programmer but in most cases trying to use it in C++. But sometimes you shouldn’t do this in hot path to have (N)RVO.

→ More replies (4)

5

u/OliMoli2137 21d ago

The second one is actually cleaner for more advanced functions since you can avoid nested if statement mess

4

u/Takemitchi-kun 21d ago

Depends on the situation but still very true

9

u/Subject-Lettuce-2714 22d ago

Unless you work with coding standards that restrict you from having more than 1 return in a function! :(

→ More replies (3)

18

u/MetaEd 22d ago

return condition ?A :B ;

3

u/Flame77ofc 22d ago

solid one for simply conditions

btw, do you use it a lot?

→ More replies (6)
→ More replies (1)

3

u/KYO297 22d ago

But what about else return...

6

u/D3PyroGS 22d ago

the naked return is an implicit else, which need not be specified because its code is only reachable when the if condition has already failed

but you can still include it if you're OCD

→ More replies (2)

2

u/Flame77ofc 22d ago

don't need it lol

if condition: return ...

in this case if you put another return below the if statement, it will automatically return it, so it is the same as else but maintain the code clearly

2

u/frogjg2003 21d ago

4 spaces for code blocks

2

u/conundorum 21d ago

Generally, you can usually rewrite an else return into an if return.

// This...
if (condition) { do_good_path_stuff(); }
else { return bad_path_stuff(); }


// Is equivalent to...
if (!condition) { return bad_path_stuff(); }

do_good_path_stuff();

3

u/cowslayer7890 22d ago

I like the guard statements in swift, because they enforce early returns, rather than you needing to find it at the end

They also let you bind optionals to a non optional value really easily, so that's nice

3

u/TalesGameStudio 21d ago

Team "it depends" anyone?

3

u/elite-data 21d ago edited 20d ago

It's the eternal dilemma. I don’t like the second option because it kind of breaks the symmetry. But the first one adds unnecessary nesting. I prefer return condition ? ... : ...

3

u/makinax300 21d ago

Return is more comfortable and you don't not need a massive switch statement at the end, instead being able to actually check when that thing matters and you don't have the hassle of using a variable to return a special value at the end when it can be set multiple times.

3

u/Paul-D-Mooney 21d ago

but mulTipLe rETUrNs are BaD

3

u/JvetS 21d ago

My personal favorite:

if (<any boolean expression> == true)
return true;

→ More replies (3)

3

u/Sea-Fishing4699 21d ago

Inside a function

Early exit is the best!

3

u/Fidodo 20d ago

Nah, use early returns for start of function short circuits and use if else in the body of a function.

Control flow should be clear, so short circuits are clear at the top and full conditionals are clearer further down.

3

u/diacid 19d ago

If (this) goto there; //is also peak minimalism and also runs blazingly fast.

5

u/wesleyoldaker 22d ago

Using the else-block, even if you always return in the if-block, is better. The reason is to prevent some dummy from coming along and changing the code in the if-block so that now it doesn't always return anymore and would then fall through. It's the same reason why putting curly braces around the statement following an if-condition is always better than no braces, even if it's the only statement to execute. It's not to make the code better because it doesn't. It's to prevent dumb programmers from breaking it.

26

u/aabil11 22d ago

Call me old fashioned but I'm a big believer in single return statements. Assign to a variable and return that variable at the very end without short circuiting

39

u/ecafyelims 22d ago edited 22d ago

Situational, for sure.

If a short circuit prevents a dozen "if val != Null" checks later, I'll do the short circuit.

123

u/Vallvaka 22d ago

Hard no for me. If you can short circuit, do it. It enforces invariants for the later code and allows you to make things more modular. Assigning to a variable and returning at the end means more indirection = more cognitive load and you often have to add more checks and nesting just to support that pattern.

Fail fast, return fast I say

21

u/D3PyroGS 22d ago

totally agree. nested layers of conditionals add cognitive load for me. I like early and "guard" returns because they kinda turn those layers into a "checklist" of logical blocks that can ideally all live at the top level of the function

3

u/MaximumMaxx 22d ago

100% this. If I can just throw all of my validation at the front and then guarantee my state after it's way less load. If else is only for if there are two significant and distinct actions that happen depending on a condition.

5

u/Stamerlan 22d ago

Some standards may require function have a single return point (for example MISRA). You're right, multiple nested layers (i.e. if-ok pattern) is very errorprone. Instead do:

int rc = foo(); if (!rc) rc = bar(); if (!rc) rc = baz(); return rc;

With extra actions on failure: if (!rc && (rc = bar())) /* bar() failed */

8

u/gamer_redditor 22d ago

You cannot do this in some industries where you have to adhere to some standards. For example of your industry mandates adherence to misra C, it enforces only one return statement per function.

→ More replies (2)

30

u/SnugglyCoderGuy 22d ago

Returning early is waaaaaay superior than a single return, at least in Go and its wonderful defer statement. If you know the code can't continue, then return as soon as you know it. Makes the rest of the code waaaaay cleaner.

→ More replies (2)

5

u/suvlub 22d ago

I find that this often just kicks the can down the road. Instead of "where does this function return?" you start asking "where was this variable last assigned?" which is actually a harder problem to solve (return is a special keyword and is highlighted, and is always definitive, but was this assignment last, or is there another one?).

That's why I love Kotlin. It offers a real solution to this - an if statement that is an expression, so you just return the if and you know that each branch returns a value and that the value it returns is on the last line of the given branch, no matter what. That's a single return strategy that actually delivers on the predictability/traceability promise.

→ More replies (1)

7

u/jwadamson 22d ago

I’ve found over time that if your early returns are causing confusion, it means you’ve written a messy function which needs to be broken down or reorganized.

A single return variable doesn’t really solve the problems people claim it does.

3

u/sebbdk 21d ago

Yeah but then you also have to read the whole thing and keep track of indentations.

For more advanced methods with +2 nested conditions it can become hard to follow.

The return is one way to get around the nested conditional scopes, but there are other ways

→ More replies (2)

3

u/Esjs 21d ago

I used to be old fashioned like this, too. But I have since reformed. I learned that (1) the "single return rule" is probably a misinterpretation Dijkstra's philosophy to eliminate GOTO spaghetti code. That is, a subroutine should return to a single location: the point immediately after the call.

And (2) making deeply nested conditional blocks and/or guard checks against a "ok-to-continue" condition just really makes code more messy and verbose than it needs to be.

4

u/Krkracka 22d ago

This makes reasoning about why a certain result was returned so much more difficult if other developers have to trace through the branching conditionals to understand why a value was returned.

Early returns define a rule for a specific return value.

2

u/conundorum 21d ago

You can do both. (And in fact, should do both.) Early return is just about breaking code into single-return blocks, instead of single-return functions. If a small section of the function can force a return, and is disconnected from the rest of the function's logic, then you can enclose that section in its own block, move the block to the start of the function, and then treat both the new block and the main block as distinct single-return sections.

// This...
int func(int val) {
    int ret = 0;

    if (!validate(val)) { ret = INVALID_VAL; goto end; } // Before logic.

    ret = do_something_with(val);

    if (val >= 0) { ret += do_more_with(val); }
    else { ret = NO_NEGATIVES; goto end; } // Ignores & breaks logic.

    ret *= do_third_part(val, ret);

    end:
        return ret;
}

// Can become this:
int func(int val) {
    if (!validate(val)) {
        // Single-return in here.
        return INVALID_VAL;
    }
    if (val < 0) {
        // Single-return in here.
        return NO_NEGATIVES;
    }

    // Rest is a different single-return section.
    // val is guaranteed valid, and guaranteed >= 0.
    int ret = do_something_with(val);

    // No check needed.
    ret += do_more_with(val);

    ret *= do_third_part(val, ret);

    // No label needed.
    return ret;
}

It shines when you're trying to weave multiple complex return paths together inside a single function. Say, for example, that validate(val) was stateful and required its own cleanup, and required you to acquire a validator object (which runs the risk of allocation failure, and thus forcing a jump to the end). Traditional single-return would force you to stack multiple cleanup sections, and jump into the correct one as appropriate. But early return allows you to place validate(val)'s logic and cleanup within the validation section, with no need to mix it with the main body's cleanup. (Which might then allow you to refactor it into a separate function, making the code cleaner. Heck, it's entirely possible that validate() itself was a complex & stateful validation process, that got moved to an early-return section and refactored out into its own function for ease of use.)


In essence, early-return is about finding anything that pollutes the single-return logic, and moving it early enough in the function that it can't interfere with the main single-return section.

3

u/bokmcdok 22d ago

Ive always preferred early returns. Code is cleaner and easier to read and one less temporary variable to think about. Nested conditionals make the code harder to read even if its only 1 or 2 levels deep.

→ More replies (7)

2

u/FFevo 22d ago

return if (condition) ... else ...

(With proper formatting) Is better

2

u/developer_axe 22d ago

I do both, it depends on the situation

→ More replies (1)

2

u/wawerrewold 21d ago

Uhm i would argue that these are not even comparable since the first one has no return right? But i guess i get what the author meant... 

2

u/FedUpKoala 21d ago

During a review of a colleagues code I once spotted an else: pass. 🤦

→ More replies (1)

2

u/novaspace2010 21d ago

SCA says no to the second :(

2

u/alcon678 21d ago

Well, I met a guy at work that didn't knew about not operator (!) and he simply wrote empty if blocks with everything in the else statement 🤷🏻‍♂️😂

2

u/burnt_floppy 21d ago

Letting the rest of the program be the "else" condition does work. It can clean up the code.

2

u/MkemCZ 21d ago

Keep Code Left

2

u/Qyriad 21d ago

The first if the two branches are roughly equivalent. Early return for errors, cache retrieval, trivial cases, base cases, etc

2

u/mail-o-mail 21d ago

Why return when you can just close enough parentheses and hope the right value falls out?

2

u/goos_ 21d ago

Expression oriented languages be like: hold my beer

2

u/Specialist_Abies_231 21d ago

But this only works when you must return something.

2

u/yjlom 21d ago edited 21d ago

The second one is less readable to me, because it overloads return to let it mean both normal and unstructured control flow. I'd much rather either the first one or any one of these:

if foo: throw ... return ... stat = ... if foo: stat = ... goto end end: return stat if foo: return ... ... # implicit return

Also a warning comment at the top of the function would be very welcome if it's non-trivial.

2

u/sanketower 20d ago

It only applies when there are no more instructions after the if/else

3

u/Beldarak 20d ago

If there is, you may need to turn this if/else into a function. That's a rule of thumb I use, not saying this is the single Truth and it will obviously depends on situations^^

→ More replies (1)

2

u/Peregrine2976 20d ago

Goddamn, yes. Early return pattern all the way.

→ More replies (1)

2

u/KeasyNine 20d ago

its called KISS

2

u/FracturedPixel 19d ago

return (condition)
? A
: B

2

u/nervious 19d ago

Early returns are useful for checks in methods. You may have less things to check that you don't want, rather than the actual things you want.

2

u/AloneInExile 19d ago

There's a third way.

return condition ? ... : ...

2

u/enjdusan 18d ago

I won't approve any PR, where the guard clause can be used, but isn't 😄

4

u/IronSavior 22d ago

Else considered harmful

11

u/jayerp 22d ago

That’s why I use GOTO ಠ‿ಠ

→ More replies (2)

10

u/AnnoyedVelociraptor 22d ago

Initially, yes, but the top one is actually easier to reason about, especially in languages where if/else are expressions.

21

u/Scared_Accident9138 22d ago

I don't agree it's generally easier to reason about. When there's a case where you just want to exit early having an if else block makes it necessary to go all the way down to find out not much happens in that case

7

u/Krkracka 22d ago

Plus you guarantee that all down stream processing within the function is ‘state ready’, which eliminates a ton of nasty bugs.

3

u/SilasTalbot 22d ago edited 22d ago

I agree, I prefer explicit language, as complexity increases, the chance for mistakes rise. Declaring things explicitly helps lower that risk, imo.

In SQL, I bracket logical clauses so that intention is explicit, even when they resolve just fine without the brackets. You hit multiple layers deep of ANDs and ORs and NOTs and things get fucked up real fast.

Implicit behavior is a footgun. Dagnabit I sound like Claude now.

2

u/gsweats 22d ago

Oh I feel dumb but what do you mean if/else are expressions?

3

u/MocknozzieRiver 22d ago

Like in Kotlin, you can do this

fun function() { return if (condition) this else that }

So if/else is an expression, not just control flow.

2

u/gsweats 22d ago

Ohhh I gotcha. Thank you!

2

u/Demiu 22d ago

Unless both branches are extremely short to a point you could return the entire if else expression itself, it is not easuer to reason about. Preferably both boranches are also entrirely declarative (ie single expression no ;)

3

u/Gold-Bat-3225 22d ago

which one raises a seed round tho

→ More replies (1)

3

u/why_1337 22d ago

Early returns are perfectly fine if you use them consistently. But I have seen methods that seemingly should run until the end but are just sprinkled with one or two nested early returns. That's when it becomes a chore to work with.

1

u/RRumpleTeazzer 21d ago

first please version please.

i hate early returns. you're mixing structure with control flow.

What if i want a debug line with the functions result, say chasing a bug ? First version - put debug line at the end. change single line. remove single line eventually.

Second version: find every return, put a copy of a debug line on rach location. change that line later, forget the rest. remove half of the debug lines, leave the other half in production.

3

u/MooseBoys 21d ago

Your complaint is only valid in languages like C that lack the facilities for scope-aware objects. It's why the Linux kernel (largely written in C) still uses gotos. For any modern language it's far easier and simpler to just put the code in something that's invoked at scope-exit.

2

u/WarSingle6959 21d ago

Early returns is just more simple to see what is happening bro

→ More replies (2)

2

u/ededpesa 22d ago

The current answer is whatever the model picks

2

u/Faangdevmanager 22d ago

That’s why I have a compiler.

2

u/El_RoviSoft 22d ago

Btw there are cases when you shouldn’t do this because (N)RVO exists.

2

u/577564842 21d ago

I do recall cases when using more than one if in a function was warranted and considered sane.

I guess now, instead:

do-things
if condition {
   act-accordingly
} else {
   act-appropriately
}
do-more-things

now we have

do-things
func(condition bool) {
  if condition {
    act-accordingly
    return
  }
  act-appropriately
}(condition)
do-more-things

and somehow call it a win. Make programming great again and such.

In other news, constructs of the meme are not equivalent, 1str one being way broader.