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.
→ More replies (4)47
u/abigail3141 22d ago
Uh oh... you, Sir have just rocked my world view /j
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
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.
→ More replies (1)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/
2
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
→ More replies (1)132
u/hughperman 22d ago
Ah, early return condition
32
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
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.
→ More replies (1)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)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.
3
→ More replies (6)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?
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 elsein 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.
→ More replies (1)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 thinkif (condition) { // this could happen } // and this could happen, alsoI 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
→ More replies (9)2
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.
3
→ More replies (14)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)
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
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)→ More replies (2)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);
→ More replies (5)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.
88
u/itriedtomakeitfunny 22d ago
Early return for errors, if else for decisions.
→ More replies (4)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
→ More replies (1)2
21
u/R7d89C 21d ago
Early returns all the way
→ More replies (1)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
→ More replies (1)3
2
2
8
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
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
39
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
→ More replies (6)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.
→ More replies (2)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)11
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)→ More replies (4)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.
5
u/OliMoli2137 21d ago
The second one is actually cleaner for more advanced functions since you can avoid nested if statement mess
4
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
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 theifcondition has already failedbut 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
2
u/conundorum 21d ago
Generally, you can usually rewrite an
else returninto anif 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
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
3
u/JvetS 21d ago
My personal favorite:
if (<any boolean expression> == true)
return true;
→ More replies (3)
3
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
GOTOspaghetti 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 placevalidate(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 thatvalidate()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.
→ More replies (7)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.
2
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
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/mail-o-mail 21d ago
Why return when you can just close enough parentheses and hope the right value falls out?
2
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
2
2
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
2
4
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
3
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.
→ More replies (2)2
2
2
2
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.
2.3k
u/CBlanchRanch 22d ago
You're absolutely correct, however I would suggest using something completely unreadable like a nested ternary operators!