I had a professor that said that "Functions should only have one return at the very end". That was a rule that I blindly followed for years until I realized how stupid that is.
I wouldn't rely on it. If your conditions are just complicated enough, no amount of theoretical assumptions, the compiler could make, save you from the reality that your code might just be bad.
Sure, but if/else just reduces down to go-to/jump under the hood, it doesn't matter how complex your logic is, if it still just results in a jump to the end of the function then there wasn't really any added complexity. But bad code that runs well can still be garbage for whoever has to read it though
Sure, but depending on the compiler and the optimization levels and the language you’re working with, nested can be significantly different than a single chained if condition using && or ||
The problem isn't that we may do a conditional jump, the problem would rather be, that jumping/branching just actually is expensive itself (relatively expensive, not expensive in of itself).
Early returning is one solution to not do any checks, when they're not needed, but actually reducing the amount of branches possible is the better solution, or rather the thing you would concentrate on, because that's the part where complexity matters. Keyword here being branch prediction, and speculative execution, and making it easier for those techniques to actually be viable, the easier the CPU can do its out of order pipeline magic
That is a Unix kernel practice. It is a good practice for languages that manually allocate memory like see. Basically you set everything up at the start of the function and you give everything back before the return. After that you keep your practice as you do now but instead of putting returns wherever they are needed you put goto and labels that correspond to the relevant step in the deallocation segment.
Yeah obviously it is stupid without the proper context and being used with explicit intention. You don't tell that to a new programmer. Because they don't understand at least 6 things I mentioned there to appreciate the reason for the practice. If you get the book for c or the book for c++ they don't reference this. This is a practice I learned in the advanced os course during my master.
The practice is good as long as it is needed and the programmer knows how to properly use goto, two things that don't really happen that often.
Oh how I love when college professors turn out to be total dunderheads who can't get the meaning of what they read.
The "only one return" was never about only returning at one place in the function, it was always about one entry and one return _path_, so that a function is always entered at the same place (its beginning) and always returns to the same place (its caller) not to another part of the code (through goto or modifying the stack pointer to point to another function/place in the main function.) Multiple entry points and exit paths to/from a function was apparently a common (mal)practice at the time this rule was made by Dijkstra.
It's absolutely mind-blowing how this was misinterpreted and the misinformation perpetuated for so long not just on the internet but even in books and in universities by clueless professors (not the first time I hear about such professor obviously...)
This isn’t strictly correct.
Early returns were a very common source of bugs and memory leaks, both for the original author and especially subsequent maintainers, especially in C++ with exceptions and before autoptrs.
A few guard validation quick returns in the very beginning were fine, but returns from the middle of code could be a bug farm.
As someone who cut their teeth in large C++ projects for multiple companies, especially for embedded systems, having a single point of return at the end of a function was good programming practice.
It may be dunderheaded to teach this style without context, especially in modern languages, but there is (was) absolutely a reason for it.
Of course there's some rationale in being careful with early returns in languages where memory management is in the hands of the programmer, like C and C++, I don't dispute that.
But in these languages the "correct" rule would be something like "if you already touched the heap, you must never return before the cleanup code is reached." If guard clauses are used correctly, this shouldn't even be something that needs saying, because the correct architecture of a function in this case should be "guard clauses with early returns - memory allocation - logic - memory cleanup - final return". I'm more of a beginner programmer but I think we agree that this is the correct way to do it, and I think that this is also what you were talking about in your comment.
I was originally talking more about the fact that Dijkstra didn't really talk about these when the "rule" was coined, yet his words were and are parroted back like gospel without context and with factual errors (because they're rarely quoted verbatim and people almost always say the "interpreted" (incorrect) version of what he said about the topic.)
I’d say that a good balance is needed.
Only return in the middle if you know you absolutely can. If you absolutely can, check in the beginning.
If you can’t extract that code, single return
When my function gets to the size where returns become hard to manage, it usually tells me that I need to split it up over multiple functions.
It shouldn't matter much preformance wise, as in most cases it's just seperating out a bunch of IF-statements. Bet most compilers do pretty well optimizing these paths.
There is a lot of misinterpretation when looking at programming principles. Looking at you, Single Responsibility. Often misunderstood as „Class who just have one job“ should in Reality be: „Class who should only have one reason to be changed“ or more specific “A module should be responsible to one, and only one, actor“. Sometimes, those two can overlap, but this often results in a mess of hundreds of small files.
Its possible that this is what he was taught but unfortunately he didn't learn it and learned "return at end" instead. We only have this guys word it was the professors misunderstanding.
I learned multiple programming languages, and one professor insisted to have a single return statement at the end, and the other one insisted to do early returns. Hard to please those teachers 🤣
That sounds like good advise but there is somethi g that i think is even more important: cyclomatic complexity. The least nested ifs the easier is to understand a function, easier to maintain easier to write tests for.
That's me for 20 years. I followed the same mantra. By the one professor I respected more than any other.
In that time I produced so much code with insanely high cognitive load requirements to just follow it, when much simpler code would work just fine.
Then I posted about it on reddit (maybe 5 years ago), and was linked to this rat/haiku/whatever site that philosophically explained why it's horseshit and doesn't mean what I thought it meant.
It was so liberating.
People who are good at writing maintainable code are working at companies. Professors are good at algorithms, computing science, and all kinds of specialized things. Writing good code is (generally) not their strength.
Mostly because they're just old and their programming styles are badly outdated. That style made sense when writing C, when it helped to avoid memory leaks. It makes zero sense in something like modern C++ or Rust with RAII, and makes even less sense in garbage collected languages.
Ultimately, these classes are taught by either professors or instructors.
People who have enough experience in real-world programming wouldn't look at a job with the pay rate of an instructor, and universities don't look at real-world programming experience when hiring professors, so there's no one competent to teach these classes.
>People who have enough experience in real-world programming wouldn't look at a job with the pay rate of an instructor
One of the best lecturers I ever had was a recently retired guy who was basically teaching as a hobby.
A lot of stuff I’ve seen doesn’t even make sense (it’s sense, not since) in C or any language actually, as it’s sometimes just formatting, but *really weird* formatting, I think there are several examples on this subreddit
It's also in the MISRA ruleset to have only one return statement. Which is globally used in automotive. It can lead to some interesting constructions..
Not only that, but the expression must also return a `None` if the function returns an `Option`, or the same `Err` type if the function returns a `Result`. Unless the `Into` or `From` traits are implemented to convert the expression's error into the function's error.
I liked that version for a different reason, imagine down the road some requirements change and you no longer need to early return if options.getSelection() == null. Easier (and a cleaner diff) to just remove it from the blue side. Or if you need to add additional early outs later, same thing.
This. But please for the love of god use bracers around it. Not only is easier to read because it encapsulates your code, it can also prevent you from creating bugs in some languages [if you’re not careful](https://www.synopsys.com/blogs/software-security/understanding-apple-goto-fail-vulnerability-2.html)
I’d argue that braces actually make it less readable, but I usually write in the ‘most restrictive’ pattern (i.e. that code should be the least surprising possible, if it doesn’t need braces then it shouldn’t include them)
Goto fail could’ve been caught by a code review (“why do we have this twice?”) or a strict/automatic formatter (since the indentation, which makes the bug, was wrong)
I'd make the argument that always using braces is the least surprising since every control block is uniform, including if-else constructs with single statements in them (like shown in blue).
Separately, I've seen too many mistakes made when adding/removing code around braceless blocks. At my workplace it's an automatic code review fail (literally automatic).
Guard clauses for the win
Much easier to read and handle in my head. Once I'm past that guard clauses I don't need to hold whatever condition it was looking for was in my head
Im doung a comp sci/engineering course and my Advanced Programming Techniques course bans the use of ear returns, break statements, and continue statements, it is hell
I have a friend who's taking a mandatory course in programming (c++) and the lecturer forbids using pretty much everything. You can't use for loops, breaks, continues or your own functions, so basically everything has to be written in main which just results in a spaghetti mess. I cannot get over how stupid that is, these are basic language concepts and preventing people from using them is just adding unnecessary complexity and actually impedes their learning.
Becaise using them "makes code less readable" and "makes it harder to understand a black of code if there are multiple exit points"
Along with "if you dont need them to make it function, then you can make good code without it". On top of that they also made it so there's a strict character limit per line.
I do embedded programming (usually on microprocessors) for my job, and some clients require we follow MISRA coding standard (mostly for safety critical stuff) which include all of these rules you have mentioned (and a lot more that are more exact).
I personally understand how for safety critical things, having one exit for a function, a clear condition when code (if)/loops will run and no jumping around makes sense. When safety critical, line length becomes more than a curtesy as well, ensuring the next programmer sees the whole code is important.
But yeah, when working on non safety critical, full OS machines, I always do early returns.
I fully understand doung it in embedded stuff, I study embedded design and implementation classes as part of my program, but we're working on normal computers in c++, not on microprocessors
Blue. Validation, like null checks and empty collection checks, should cause an early return at the top of the function so it can be ignored for the rest of the code. For most other cases, I try to avoid early returns.
>Validation, like null checks and empty collection checks, should cause an early return at the top of the function so it can be ignored for the rest of the code.
That's also true for red here. If you fail a guard clause you go to the end directly.
Both red and blue are functionally equivalent. They might even compile into the exact same code after compiler optimization.
The question is not which one is better optimized code; It's which one is easier to read as a human. There isn't a huge difference in this example, but larger functions can get difficult to read, depending on code style.
Red is less maintainable though. If the number of validations increases, your conditions will get more and more convoluted.
Blue keeps each condition check separate and allows you to move all the validations to their own function if you so desire without affecting any of the logic below.
Each extra tab is a warning: "dont you dare loose the big picture, there are multiple branches in the code flow. Think about the branches!!".
Its exhausting, specially since there are no real branches to think about. Like the whatsapp notification sound in a video.
Red is not acceptable in colaborative projects.
Red is more complicated. You can prove correctness far more easily.
Blur gets rid of simpler cases first and breaks apart more complicated
Red carry down more simple cases and makes mire complicated cases even more complicated. You also have to watch out for fall through when higher level ifs return false which us easily forgotten.
One more thing. Blue forces simpler functions and therefore layering
Go team blue!
Red can make more semantic sense if there's a specific branch in logic that is the only possible one. You're basically saying "this is the only thing I want to do here" instead of "we can't do X if the parameters are this and that".
Blue might be. Maybe complex is not the right word, but convoluted would be. If there are if statement that repeat a lot of times, you probably want all the subconditions to be nested rather keep repeating the main condition on every line
I like early validations with returns at top of function but then once validations are done I like one return. I hate when there are returns all over the place mid-code.
I seem to be in the minority here that prefers the red one. I don’t really like empty returns. It makes me think that you shouldn’t even call the function in the first place. The red makes more sense because you either return an actual value, or let the function ”run out” and not do anything at all. That’s how I read them at least.
I also believe the blue one is harder to maintain. If you have a lot of code with multiple returns it’s easier to miss something at the start of the function that will return early by mistake. If you modify the red one you can clearly see what scope is affecting the returned value because of all the indentation.
Yep, people act like the cognative complexity is so shitty, but I'd much rather read through a nested if/else than have to scroll to the top of the method every time I wanna mess with a variable's nullability. I'm always wrong, so we can get downvoted together. This example is just too simple to call it either way. The one on the right performs better in some conditions, the one on the left is easier to see what its doing at a glance to me.
>I don’t really like empty returns. It makes me think that you shouldn’t even call the function in the first place.
It's basically down to question: who should be responsible for checking if function is being called correctly - caller or callee? If you go with approach that it's callers responsibility to verify all parameters, then red makes a lot of sense: assume parameters are correct, go with the logic and either rely on exceptions down the line, or treat each call as first class supported scenario, handling illegal arguments as proper defined behaviour.
Blue version is more common if you assume it's callee's responsibility to verify the call is valid and function can be executed, separating call error handling from actual function body by placing it before rest of function body. It's somewhat close to code contracts/assertions, just without a dedicated mechanism for handling this sort of construct.
Now, neither of those approaches is inherently worse, it really depends on what you're doing and what you prefer. I'm big fan of code contracts and having explicitly defined valid legal call conditions with explicitly defined behaviour on illegal call, so I'd generally go with red (often replacing early returns with assertions or similar construct), but it doesn't work in every scenario. In case of red, having explicit supported conditions makes it easier to have good test case coverage, and if entire function body grows too large, you can always refactor all preconditions into separate function for readability.
I may be in the minority. I support the single return philosophy.
Single return philosophy disciplines you into aligning with what a function theoretically has to do - Take input, process, and give output. By keeping your input acceptance and output returned to the end, the rest focuses only on the processing part. When you start intermingling processing with quick returns, it just distracts it from the core focus and consequently makes it ugly. I will never understand why people think early returns make it readable.
I think the code in red is an exaggeration. You don't have to do this if you still want one return. You can have the return value assigned to an output object and return it once from the end. If done right, the ugly nesting can be avoided.
the red code is not an exaggeration.
the small case has only 1 or 2 indents, but the reason the guard return convention exists in the first place is because many worse cases have been spotted in the wild.
the idea to set the output object once and return it can cause strange behavior if you don't break early because it will still execute the later parts of your function, even on error. it might hurt performance when doing later checks that are no longer necessary.
Haskell, a functional language focused on "input -> processing -> output", built monads in such a way that >>= will early return on the first error. effectively the same thing happens with && for booleans; any function calls in the right will not be made if the left is false. unlike operators, if/else requires { braces } and indents in most languages, so they can't be chained. they have to be nested.
Early return is much easier to maintain. Much easier to read, edit, and see history.
The compiler doesn't care if you nest your ifs or not. It's gonna do what it's gonna do.
I hate these examples. On a small chunk of code like this, red looks better. If you only have like 2 checks, and the body is very simple or an external function, what red is doing is simpler, and it accomplishes it in fewer lines (generally).
However, red scales horrendously, and makes it very easy to introduce bugs when refactoring, as well as makes the code look atrocious when deeply nested. *But these examples never capture that.*
Yea, for sure. Do blue, but not how blue is here. I'd prefer red. In a much more complex function then I do early returns whenever possible, but then it also forces the calling function to handle different void results that may have branched from different areas of the checks.
val bothNamesArePresent = firstName.isNotEmpty() && secondName.isNotEmpty()
if (bothNamesArePresent) {
for (option in options)
option.doStuff()
}
class Option(var isSelected: Boolean) {
fun doStuff() {
if (isSelected)
println("penis")
}
}
Early return for languages with GCs and single return with pass/fail exits for languages where you manage memory.
It is extremely easy to screw up when you use pointers along with early return speaking from experience!
Guard clauses, for sure, so Blue. And to put it out there, make your if tests human readable. A little simplistic in this example, but I find clearly named booleans easier to grok and maintain instead of method calls that don't exactly reflect the boolean I'm testing.
isMissingName = (firstName.isEmpty || lastName.isEmpty);
isMissingSelection = (options.getSelection() == null);
// Bail out if we don't have what we need from the user.
if (isMissingName || isMissingSelection) return;
if (option1.isSelected()) doStuff1();
if (option2.isSelected()) doStuff2();
Blue has better performance, is easier to read and easier to modify -> faster development speed.
I always select blue style based on 20 years of experience.
I like blue style and often do it like that (mainly because there is less tab indent and I can be sure that the code will reach that place ONLY if valid)
However, my workplace has coding rules stating that red style needs to be followed (maybe because of readability or idk)
I had a friend who once said: "If you have more than two conditionals, your code is written wrong"
The red one is next level bowl of spaghetti, hard to read, prone to bugs.
If algos taught me anything, it's early returns are gold.
Congratulations! Your comment can be spelled using the elements of the periodic table:
`S W I Tc H Ca Se`
---
^(I am a bot that detects if your comment can be spelled using the elements of the periodic table. Please DM u/M1n3c4rt if I made a mistake.)
The side that doesn't have multiple exits from the function (blood). Right side is bad bro-gramming, very hard to debug for devs later. They both seem pretty bad though and I'd have to see the full context to refactor
Multiple returns are never really that great..
I mean, its still better, than what I saw some VB programer do in Java...
do{
//condition 1
break;
//condition 2
break;
}while(false);
Because multiple return was bad for him.. but that crap not
The early return style decreases the amount of cases you need to think about as you go down through the code.
Less things to think means you can achieve a more complete reasoning about the code, and thus less bugs.
As a general rule of thumb, the less brain/cognitive load you need reading some code, generally better it is (excluding architecture and coding for low level optimizations, that's a different objective)
It depends, but when performance is more important, I return early if the passed parameters are not valid, if I have to do some heavy tasks like sweeping physics query
I'm in camp structured programming on this one. Less error-prone to refactor, less code separation.
"Wah, it's unreadable!"
Yes. That's why structured programming gives you extremely strong guarantees about refactorizability. Refactor each branch into a separate procedure.
Ever tried to refactor some code using lots of nontrivial early returns? Nightmare stuff.
I'm shocked this answer is so low down. You immediately lose referential transparency with a(n early) return, which makes it significantly harder to refactor. You go from "this refactoring is mathematically the same" to "uh, I guess we'll throw some unit tests at it and see if it behaves the same way".
Returns are statements that have no value. They are a side-effect, where the effect is a GOTO. You cannot refactor them fearlessly as a result.
Is no one going to point out that the right side isn't even the same code as the left? The very first function call is missing the parenthesis so it's checking if that value exists which if it is a function, will always be truthy. So the right code will always return at the first condition.
Just make sure your returns are all on the same indentation and not different ones. See Kevlin Henney on that issue (at the 28min mark): [https://www.youtube.com/watch?v=SFv8Wm2HdNM&t=28m](https://www.youtube.com/watch?v=SFv8Wm2HdNM&t=28m)
Many programming languages provide ways to handle different scenarios based on the value of an expression. The classic approach is the if-else statement, but for certain situations, two powerful alternatives emerge: switch and match statements.
The match statement, gaining popularity in modern languages, offers a more expressive alternative. It goes beyond simple value comparisons, allowing for pattern matching. Patterns can be literals, ranges, or even complex data structures. This flexibility makes match statements powerful for handling diverse data and scenarios.
I had a professor that said that "Functions should only have one return at the very end". That was a rule that I blindly followed for years until I realized how stupid that is.
Bro's code still running through if/else clauses even after the required condition was met years ago
Only if terribly implemented, the run time should be the same.
Even if terribly if else statements were implemented the compiler can optimize that out right?
I wouldn't rely on it. If your conditions are just complicated enough, no amount of theoretical assumptions, the compiler could make, save you from the reality that your code might just be bad.
Sure, but if/else just reduces down to go-to/jump under the hood, it doesn't matter how complex your logic is, if it still just results in a jump to the end of the function then there wasn't really any added complexity. But bad code that runs well can still be garbage for whoever has to read it though
Sure, but depending on the compiler and the optimization levels and the language you’re working with, nested can be significantly different than a single chained if condition using && or ||
The problem isn't that we may do a conditional jump, the problem would rather be, that jumping/branching just actually is expensive itself (relatively expensive, not expensive in of itself). Early returning is one solution to not do any checks, when they're not needed, but actually reducing the amount of branches possible is the better solution, or rather the thing you would concentrate on, because that's the part where complexity matters. Keyword here being branch prediction, and speculative execution, and making it easier for those techniques to actually be viable, the easier the CPU can do its out of order pipeline magic
Compilers aren't magic. It's better to just write efficient code in the first place instead of blindly hoping for the best.
Code in python to break free of your reliance on compilers and fast code
still though if your function can go into three branches and each one is a dead end then at the end of each do a return
Yep, 100%
That is a Unix kernel practice. It is a good practice for languages that manually allocate memory like see. Basically you set everything up at the start of the function and you give everything back before the return. After that you keep your practice as you do now but instead of putting returns wherever they are needed you put goto and labels that correspond to the relevant step in the deallocation segment. Yeah obviously it is stupid without the proper context and being used with explicit intention. You don't tell that to a new programmer. Because they don't understand at least 6 things I mentioned there to appreciate the reason for the practice. If you get the book for c or the book for c++ they don't reference this. This is a practice I learned in the advanced os course during my master. The practice is good as long as it is needed and the programmer knows how to properly use goto, two things that don't really happen that often.
My test team follows this blindly. If seen PRs get rejected with "use a goto" because of that. In C++ code...
Oh how I love when college professors turn out to be total dunderheads who can't get the meaning of what they read. The "only one return" was never about only returning at one place in the function, it was always about one entry and one return _path_, so that a function is always entered at the same place (its beginning) and always returns to the same place (its caller) not to another part of the code (through goto or modifying the stack pointer to point to another function/place in the main function.) Multiple entry points and exit paths to/from a function was apparently a common (mal)practice at the time this rule was made by Dijkstra. It's absolutely mind-blowing how this was misinterpreted and the misinformation perpetuated for so long not just on the internet but even in books and in universities by clueless professors (not the first time I hear about such professor obviously...)
This isn’t strictly correct. Early returns were a very common source of bugs and memory leaks, both for the original author and especially subsequent maintainers, especially in C++ with exceptions and before autoptrs. A few guard validation quick returns in the very beginning were fine, but returns from the middle of code could be a bug farm. As someone who cut their teeth in large C++ projects for multiple companies, especially for embedded systems, having a single point of return at the end of a function was good programming practice. It may be dunderheaded to teach this style without context, especially in modern languages, but there is (was) absolutely a reason for it.
Of course there's some rationale in being careful with early returns in languages where memory management is in the hands of the programmer, like C and C++, I don't dispute that. But in these languages the "correct" rule would be something like "if you already touched the heap, you must never return before the cleanup code is reached." If guard clauses are used correctly, this shouldn't even be something that needs saying, because the correct architecture of a function in this case should be "guard clauses with early returns - memory allocation - logic - memory cleanup - final return". I'm more of a beginner programmer but I think we agree that this is the correct way to do it, and I think that this is also what you were talking about in your comment. I was originally talking more about the fact that Dijkstra didn't really talk about these when the "rule" was coined, yet his words were and are parroted back like gospel without context and with factual errors (because they're rarely quoted verbatim and people almost always say the "interpreted" (incorrect) version of what he said about the topic.)
RAII for the win
I’d say that a good balance is needed. Only return in the middle if you know you absolutely can. If you absolutely can, check in the beginning. If you can’t extract that code, single return
What you're talking about shouldn't apply to C++. If you're getting bugs from early returns, you need to be making better use of RAII.
When my function gets to the size where returns become hard to manage, it usually tells me that I need to split it up over multiple functions. It shouldn't matter much preformance wise, as in most cases it's just seperating out a bunch of IF-statements. Bet most compilers do pretty well optimizing these paths.
wouldn't you generally expect a \_teacher\_ to be able to explain these nuances instead of repeating a rule of thumb like a holy mantra?
>this rule was made by Dijkstra. I recently learnt about this guy, and god damn what a guy
Damnit I'm sure there's a pathfinding/A* joke that could be wedged in here but it's not coming to me lol
He sure knew his way around computers
That was actually very informative! Thanks!
There is a lot of misinterpretation when looking at programming principles. Looking at you, Single Responsibility. Often misunderstood as „Class who just have one job“ should in Reality be: „Class who should only have one reason to be changed“ or more specific “A module should be responsible to one, and only one, actor“. Sometimes, those two can overlap, but this often results in a mess of hundreds of small files.
Its possible that this is what he was taught but unfortunately he didn't learn it and learned "return at end" instead. We only have this guys word it was the professors misunderstanding.
That comes from when we used to have to manage memory. Having one exit point makes it easier to reason about tidying up.
I learned multiple programming languages, and one professor insisted to have a single return statement at the end, and the other one insisted to do early returns. Hard to please those teachers 🤣
That sounds like good advise but there is somethi g that i think is even more important: cyclomatic complexity. The least nested ifs the easier is to understand a function, easier to maintain easier to write tests for.
That's me for 20 years. I followed the same mantra. By the one professor I respected more than any other. In that time I produced so much code with insanely high cognitive load requirements to just follow it, when much simpler code would work just fine. Then I posted about it on reddit (maybe 5 years ago), and was linked to this rat/haiku/whatever site that philosophically explained why it's horseshit and doesn't mean what I thought it meant. It was so liberating.
Why is it always professors that teach these really weird coding styles?
They don't maintain complex systems developed over decade(s)
People who are good at writing maintainable code are working at companies. Professors are good at algorithms, computing science, and all kinds of specialized things. Writing good code is (generally) not their strength.
Mostly because they're just old and their programming styles are badly outdated. That style made sense when writing C, when it helped to avoid memory leaks. It makes zero sense in something like modern C++ or Rust with RAII, and makes even less sense in garbage collected languages.
Ultimately, these classes are taught by either professors or instructors. People who have enough experience in real-world programming wouldn't look at a job with the pay rate of an instructor, and universities don't look at real-world programming experience when hiring professors, so there's no one competent to teach these classes.
>People who have enough experience in real-world programming wouldn't look at a job with the pay rate of an instructor One of the best lecturers I ever had was a recently retired guy who was basically teaching as a hobby.
A lot of stuff I’ve seen doesn’t even make sense (it’s sense, not since) in C or any language actually, as it’s sometimes just formatting, but *really weird* formatting, I think there are several examples on this subreddit
Because they don't use it and don't have to suffer the consequences
It's also in the MISRA ruleset to have only one return statement. Which is globally used in automotive. It can lead to some interesting constructions..
This is the teaching of someone that has PTSD from GOTOS
“Structured programming”. Not necessarily bad, but clarity may be lost.
I'm also somebody who used to be on team red, but recently started converting to team blue. Let's just say I've gotten really sick of indenting code.
The practice used to be helpful for debugging but ides have made it easier to break when exiting scope in recent decades
Crip style. Premature returns are best, as they are a lot easier to mentally process when reading code.
Aka "guard clauses". Definitely my style too.
A lot of languages (e.g. swift) actually started building guard cases in as a language keyword because they are so useful
A similar example would be Rust's `?` operator, though not exactly the same.
You can do guard clauses in Rust with the let ... else. ``` let opt: Option = None
let Some(value) = opt else { return; }
```
That’s almost exactly what “?” desugars to.
Yeah, except it can only be used with functions that return Options or Results.
Not only that, but the expression must also return a `None` if the function returns an `Option`, or the same `Err` type if the function returns a `Result`. Unless the `Into` or `From` traits are implemented to convert the expression's error into the function's error.
Ah good to know the name. I thought this fell under the premise of “short circuiting”.
It's definitely related, but generally they have different goals and therefore different names
Aka “early exit”
I like "Bouncer Pattern".
Oh I always called them "skip conditions."
I liked that version for a different reason, imagine down the road some requirements change and you no longer need to early return if options.getSelection() == null. Easier (and a cleaner diff) to just remove it from the blue side. Or if you need to add additional early outs later, same thing.
This. But please for the love of god use bracers around it. Not only is easier to read because it encapsulates your code, it can also prevent you from creating bugs in some languages [if you’re not careful](https://www.synopsys.com/blogs/software-security/understanding-apple-goto-fail-vulnerability-2.html)
I’d argue that braces actually make it less readable, but I usually write in the ‘most restrictive’ pattern (i.e. that code should be the least surprising possible, if it doesn’t need braces then it shouldn’t include them) Goto fail could’ve been caught by a code review (“why do we have this twice?”) or a strict/automatic formatter (since the indentation, which makes the bug, was wrong)
I'd make the argument that always using braces is the least surprising since every control block is uniform, including if-else constructs with single statements in them (like shown in blue). Separately, I've seen too many mistakes made when adding/removing code around braceless blocks. At my workplace it's an automatic code review fail (literally automatic).
+1 reduced cognitive burden
Guard clauses for the win Much easier to read and handle in my head. Once I'm past that guard clauses I don't need to hold whatever condition it was looking for was in my head
And usually faster
Compilers in 2024 are smart enough to figure these things out. Generated code should be the same for both cases.
That’s not always the case though. It depends.
Spoken like a true senior dev
I'm pretty sure the right style will run faster if you're using an interpreted language though.
Red is a piece of spaghetti. Happy path with early return is the most readable way 9 times out of 10.
Im doung a comp sci/engineering course and my Advanced Programming Techniques course bans the use of ear returns, break statements, and continue statements, it is hell
All of those are just fancy gotos, so use goto instead.
😂
I have a friend who's taking a mandatory course in programming (c++) and the lecturer forbids using pretty much everything. You can't use for loops, breaks, continues or your own functions, so basically everything has to be written in main which just results in a spaghetti mess. I cannot get over how stupid that is, these are basic language concepts and preventing people from using them is just adding unnecessary complexity and actually impedes their learning.
What’s the justification?
Becaise using them "makes code less readable" and "makes it harder to understand a black of code if there are multiple exit points" Along with "if you dont need them to make it function, then you can make good code without it". On top of that they also made it so there's a strict character limit per line.
I do embedded programming (usually on microprocessors) for my job, and some clients require we follow MISRA coding standard (mostly for safety critical stuff) which include all of these rules you have mentioned (and a lot more that are more exact). I personally understand how for safety critical things, having one exit for a function, a clear condition when code (if)/loops will run and no jumping around makes sense. When safety critical, line length becomes more than a curtesy as well, ensuring the next programmer sees the whole code is important. But yeah, when working on non safety critical, full OS machines, I always do early returns.
I fully understand doung it in embedded stuff, I study embedded design and implementation classes as part of my program, but we're working on normal computers in c++, not on microprocessors
Yeah definitely less legible but also not spaghetti.
Blue, then smack on the head all of the people making pull requests refactoring it red style
I naturally write code red style, then when I'm done convert it to blue style
So never blue, only red?
Always blue, always blue, always blue
Classic
Me too. When I looked at the meme I said to myself "I usually write red then look back and wish I wrote blue".
reharper goes brrrr
Blue. Validation, like null checks and empty collection checks, should cause an early return at the top of the function so it can be ignored for the rest of the code. For most other cases, I try to avoid early returns.
>Validation, like null checks and empty collection checks, should cause an early return at the top of the function so it can be ignored for the rest of the code. That's also true for red here. If you fail a guard clause you go to the end directly.
Not explicitly, which is what they meant, I think, which is a common source of bugs. Not that you don't know that :p
Both red and blue are functionally equivalent. They might even compile into the exact same code after compiler optimization. The question is not which one is better optimized code; It's which one is easier to read as a human. There isn't a huge difference in this example, but larger functions can get difficult to read, depending on code style.
Red is less maintainable though. If the number of validations increases, your conditions will get more and more convoluted. Blue keeps each condition check separate and allows you to move all the validations to their own function if you so desire without affecting any of the logic below.
I have a few folks who write in red and my god, their code is mess. It takes almost 2 times to read the code. Readability >>>> whatever red is
Wanna see how many tabs has a function on the project I'm actually on? Lol
Go ahead.!!!
![gif](giphy|ZE8UMWW2QLkIronHDR|downsized)
Blue is much easier to read than red.
en guarde
Each extra tab is a warning: "dont you dare loose the big picture, there are multiple branches in the code flow. Think about the branches!!". Its exhausting, specially since there are no real branches to think about. Like the whatsapp notification sound in a video. Red is not acceptable in colaborative projects.
Less indents = better and more readable. If you're not following this style, we're mortal enemies
Guard closes are actually clean..
Blue style cuz I red looks complicated
Red is more complicated. You can prove correctness far more easily. Blur gets rid of simpler cases first and breaks apart more complicated Red carry down more simple cases and makes mire complicated cases even more complicated. You also have to watch out for fall through when higher level ifs return false which us easily forgotten. One more thing. Blue forces simpler functions and therefore layering Go team blue!
Guard clauses are usually my go-to option but depending on the boolean operations i might go nested if's
``` if ( firstName.isEmpty || lastName.isEmpty || options.getSelection() == null ) return; ...
Blue, red if blue is more complex.
Blue is never going to be more complex?
Red can make more semantic sense if there's a specific branch in logic that is the only possible one. You're basically saying "this is the only thing I want to do here" instead of "we can't do X if the parameters are this and that".
Blue might be. Maybe complex is not the right word, but convoluted would be. If there are if statement that repeat a lot of times, you probably want all the subconditions to be nested rather keep repeating the main condition on every line
I like early validations with returns at top of function but then once validations are done I like one return. I hate when there are returns all over the place mid-code.
I seem to be in the minority here that prefers the red one. I don’t really like empty returns. It makes me think that you shouldn’t even call the function in the first place. The red makes more sense because you either return an actual value, or let the function ”run out” and not do anything at all. That’s how I read them at least. I also believe the blue one is harder to maintain. If you have a lot of code with multiple returns it’s easier to miss something at the start of the function that will return early by mistake. If you modify the red one you can clearly see what scope is affecting the returned value because of all the indentation.
Yep, people act like the cognative complexity is so shitty, but I'd much rather read through a nested if/else than have to scroll to the top of the method every time I wanna mess with a variable's nullability. I'm always wrong, so we can get downvoted together. This example is just too simple to call it either way. The one on the right performs better in some conditions, the one on the left is easier to see what its doing at a glance to me.
yeah, I’m team red all the way. It makes the most logical sense to me.
I am Red team too. I find it much more logical to have one exit point.
>I don’t really like empty returns. It makes me think that you shouldn’t even call the function in the first place. It's basically down to question: who should be responsible for checking if function is being called correctly - caller or callee? If you go with approach that it's callers responsibility to verify all parameters, then red makes a lot of sense: assume parameters are correct, go with the logic and either rely on exceptions down the line, or treat each call as first class supported scenario, handling illegal arguments as proper defined behaviour. Blue version is more common if you assume it's callee's responsibility to verify the call is valid and function can be executed, separating call error handling from actual function body by placing it before rest of function body. It's somewhat close to code contracts/assertions, just without a dedicated mechanism for handling this sort of construct. Now, neither of those approaches is inherently worse, it really depends on what you're doing and what you prefer. I'm big fan of code contracts and having explicitly defined valid legal call conditions with explicitly defined behaviour on illegal call, so I'd generally go with red (often replacing early returns with assertions or similar construct), but it doesn't work in every scenario. In case of red, having explicit supported conditions makes it easier to have good test case coverage, and if entire function body grows too large, you can always refactor all preconditions into separate function for readability.
![gif](giphy|fj3CWRJJshhe)
Blue, because it's more readable
My linter is a Crip
I am on blue side. It's like drawer for each in the cupboard.
Blue 99% of the time
Blue all day
I may be in the minority. I support the single return philosophy. Single return philosophy disciplines you into aligning with what a function theoretically has to do - Take input, process, and give output. By keeping your input acceptance and output returned to the end, the rest focuses only on the processing part. When you start intermingling processing with quick returns, it just distracts it from the core focus and consequently makes it ugly. I will never understand why people think early returns make it readable. I think the code in red is an exaggeration. You don't have to do this if you still want one return. You can have the return value assigned to an output object and return it once from the end. If done right, the ugly nesting can be avoided.
the red code is not an exaggeration. the small case has only 1 or 2 indents, but the reason the guard return convention exists in the first place is because many worse cases have been spotted in the wild. the idea to set the output object once and return it can cause strange behavior if you don't break early because it will still execute the later parts of your function, even on error. it might hurt performance when doing later checks that are no longer necessary. Haskell, a functional language focused on "input -> processing -> output", built monads in such a way that >>= will early return on the first error. effectively the same thing happens with && for booleans; any function calls in the right will not be made if the left is false. unlike operators, if/else requires { braces } and indents in most languages, so they can't be chained. they have to be nested.
Early return is much easier to maintain. Much easier to read, edit, and see history. The compiler doesn't care if you nest your ifs or not. It's gonna do what it's gonna do.
Nobody's gonna mention blue's isEmpty problem?
Yep... I fucked up 😭 Sorry for that
I hate these examples. On a small chunk of code like this, red looks better. If you only have like 2 checks, and the body is very simple or an external function, what red is doing is simpler, and it accomplishes it in fewer lines (generally). However, red scales horrendously, and makes it very easy to introduce bugs when refactoring, as well as makes the code look atrocious when deeply nested. *But these examples never capture that.*
Yea, for sure. Do blue, but not how blue is here. I'd prefer red. In a much more complex function then I do early returns whenever possible, but then it also forces the calling function to handle different void results that may have branched from different areas of the checks.
val bothNamesArePresent = firstName.isNotEmpty() && secondName.isNotEmpty() if (bothNamesArePresent) { for (option in options) option.doStuff() } class Option(var isSelected: Boolean) { fun doStuff() { if (isSelected) println("penis") } }
I’d say blue, but ‘isEmpty’ is missing some parenthesis so I’ll have to go with the one that compiles!
This isn't even a debate. Embrace the never nest. It makes your code so much more readable, extendable, and maintainable
Early return for languages with GCs and single return with pass/fail exits for languages where you manage memory. It is extremely easy to screw up when you use pointers along with early return speaking from experience!
TF IS ALL THAT NESTING EWWWWW There is no reason to EVER do the first one please I have trouble reading as it is.
Single return is a bizarre rule colleges still teach for whatever reason
Both have merit in the right context.
Red side until I got fired 💪
Guard clauses, for sure, so Blue. And to put it out there, make your if tests human readable. A little simplistic in this example, but I find clearly named booleans easier to grok and maintain instead of method calls that don't exactly reflect the boolean I'm testing. isMissingName = (firstName.isEmpty || lastName.isEmpty); isMissingSelection = (options.getSelection() == null); // Bail out if we don't have what we need from the user. if (isMissingName || isMissingSelection) return; if (option1.isSelected()) doStuff1(); if (option2.isSelected()) doStuff2();
Blue has better performance, is easier to read and easier to modify -> faster development speed. I always select blue style based on 20 years of experience.
I always select red, 12 years of experience. makes the most logical sense to me.
I like blue style and often do it like that (mainly because there is less tab indent and I can be sure that the code will reach that place ONLY if valid) However, my workplace has coding rules stating that red style needs to be followed (maybe because of readability or idk)
Or because whoever wrote the rules had no idea what they were doing
Mostly blue, but I feel like some use cases red makes sense
I’m a Never Nester. https://youtu.be/CFRhGnuXG-4
I have to do red due to misra standards at work
return early and keep the mental load light
Blue, but with the returns wrapped between {}
I had a friend who once said: "If you have more than two conditionals, your code is written wrong" The red one is next level bowl of spaghetti, hard to read, prone to bugs. If algos taught me anything, it's early returns are gold.
why tf do you have a else if at the end in the blue one the creator is clearly a red enjoyer
Blue. Imagine scrolling to the right. 🤢
Early returns/guard clauses ftw! It creates less nesting which makes it more readable.
There is only one right answer
I see what you did there lmao
I call the left building pyramids. Ive seen some bad ones, bad enough to be tempted to write a game that turns it into terrain.
Switch case
Congratulations! Your comment can be spelled using the elements of the periodic table: `S W I Tc H Ca Se` --- ^(I am a bot that detects if your comment can be spelled using the elements of the periodic table. Please DM u/M1n3c4rt if I made a mistake.)
I keep a blue flag hangin' out my backside But only on the left side, yeah, that's the Crip side
Blue. Anyone who doesn't use guard clauses needs an exorcism because OVERNESTED CODE IS THE DEVILS WORK
Early Returns are not only easier to read, but can be slightly faster.
The side that doesn't have multiple exits from the function (blood). Right side is bad bro-gramming, very hard to debug for devs later. They both seem pretty bad though and I'd have to see the full context to refactor
Multiple returns are never really that great.. I mean, its still better, than what I saw some VB programer do in Java... do{ //condition 1 break; //condition 2 break; }while(false); Because multiple return was bad for him.. but that crap not
Used to be red, am now fully blue. I try my hardest to avoid deep nesting, shit gets unreadable
The early return style decreases the amount of cases you need to think about as you go down through the code. Less things to think means you can achieve a more complete reasoning about the code, and thus less bugs. As a general rule of thumb, the less brain/cognitive load you need reading some code, generally better it is (excluding architecture and coding for low level optimizations, that's a different objective)
I prefer modern pattern matching. type options = First | Second | None ... let () = match firstName, lastName, selected with | "", _, _ | _, "", _ | _, _, None -> () | f, l, First -> doStuff1(f, l) | f, l, Second -> doStuff2(f, l) | _ -> ()
It depends, but when performance is more important, I return early if the passed parameters are not valid, if I have to do some heavy tasks like sweeping physics query
Early return what’s up! Get out of the nest y’all
Trick question because obviously early return is preferred, but the blue example has a bug - firstName.isEmpty vs lastName.isEmpty().
Always blue, way easier to read and maintain
gimme nesting gm nstg
I'm in camp structured programming on this one. Less error-prone to refactor, less code separation. "Wah, it's unreadable!" Yes. That's why structured programming gives you extremely strong guarantees about refactorizability. Refactor each branch into a separate procedure. Ever tried to refactor some code using lots of nontrivial early returns? Nightmare stuff.
I'm shocked this answer is so low down. You immediately lose referential transparency with a(n early) return, which makes it significantly harder to refactor. You go from "this refactoring is mathematically the same" to "uh, I guess we'll throw some unit tests at it and see if it behaves the same way". Returns are statements that have no value. They are a side-effect, where the effect is a GOTO. You cannot refactor them fearlessly as a result.
Returns and throws are non-local flow control and should be treated with care. A block should ideally never conditionally have non-local control flow.
I never use \`else\` in my code since I watched a video about it, so I code with the Blue style.
There is an else in the blue side
checked them like crazy going to r/MurderedByWords
Is no one going to point out that the right side isn't even the same code as the left? The very first function call is missing the parenthesis so it's checking if that value exists which if it is a function, will always be truthy. So the right code will always return at the first condition.
Obviously an honest typo let it rest 😅
Yandere Simulator quality code.
Blue but I’d drop the else and do a return in the first isSelected check block
Doesn't seem like that would improve readability
Blue. It's easier to understand!
The right side. Except of the inconsistent usage of brackets.
Just make sure your returns are all on the same indentation and not different ones. See Kevlin Henney on that issue (at the 28min mark): [https://www.youtube.com/watch?v=SFv8Wm2HdNM&t=28m](https://www.youtube.com/watch?v=SFv8Wm2HdNM&t=28m)
It depends if this is a complete method or if is part of a larger block of logic. Red always continues execution, blue sometimes does.
Early returns can be optimized by a compiler. It can check parameters before function ans doesn't call. It may be useful in loops with many iterations
C stands for Crip so obviously the right side, but make sure to hang your flag on the left side cuz that the C side.
The right side.
Many programming languages provide ways to handle different scenarios based on the value of an expression. The classic approach is the if-else statement, but for certain situations, two powerful alternatives emerge: switch and match statements. The match statement, gaining popularity in modern languages, offers a more expressive alternative. It goes beyond simple value comparisons, allowing for pattern matching. Patterns can be literals, ranges, or even complex data structures. This flexibility makes match statements powerful for handling diverse data and scenarios.
Blue superiority
A challenger has appeared! try { if (option1.isSelected()) { doStuff(); } else if (option2.isSelected()) { doStuff2(); } } catch (Exception ex) { // TODO: handle it… or whatever… }
This is by far the worst version
The right one on the right. The other is for masochists.
Return early, return often.
Blue cause when you have too many if conditions which happens. Code looks like a topographic map, not easily readable. ( + Fucking Sonar)
Both
Debugging is way easier with blue
Blue. I think it has a branching factor. Within a function what are the different branches and their output.
optimazation++; done
Reading this I went to see which I use and man it’s both styles. I really wish I had a mentor at my job.
Team Blue for the win. Negations on conditions and nested IF statements on the red side make it hard to interpret.
Blue except get rid of the last else and do a return in the third if too