|
I'm definitely in the single exit camp.
And, after browsing this thread, finding it very hard to argue the case for it beyond "'cause I am, that's why!"
I just like knowing there's a single exit point where I nuke that pointer if it's non-null etc.
"Look here you function - or threadproc - or whatever it is you call your self, you're not getting out of here until your hair is combed and you've buttoned your shirt."
If I were to use the multiple return paradigm I think I'd use multiple goto exit 's instead. Which seems kinda uglee.
I'm definitely in the single exit camp.
'cause I am, that's why.
|
|
|
|
|
Tim Deveaux wrote: after browsing this thread, finding it very hard to argue the case for it beyond "'cause I am, that's why!" That's a good enough reason.
Me, I see adding returns where they fit as being more efficient (which it is), but unless you're doing something really intensive like editing high-res game graphics or video (where loops and if-blocks are hit, quite literally, billion of times), it won't make a difference that's human-noticeable, so stick to what you're happy with, and what makes your code easier on your eye, when you have to revisit it.
Tim Deveaux wrote: If I were to use the multiple return paradigm I think I'd use multiple goto exit 's instead. Which seems kinda uglee. Every jump to a non-sequential line is a goto. Loops and if statements were invented to save you the trouble of writing endless goto lines, by adding them for you, in the background behind the code.
Think: What does return do that goto doesn't?
(Answer: it satisfies the anti-goto evangelists, by using a function named "return", which does nothing but call goto.)
Saying that the goto is unacceptable is saying that if and for are unacceptable. Never be afraid of using a goto in sequential code, as long as you use it intelligently.
E.g. exiting an if-block with a goto is usually fine, but exiting a loop with a goto often isn't (unless you're only using global variables, which... Yeah, no need to expound on that one).
I wanna be a eunuchs developer! Pass me a bread knife!
|
|
|
|
|
Mark_Wallace wrote: ... stick to what you're happy with
Yes - in that it's a matter of style.
If I was working on a codebase that used the fast exit religiously, I'd stick to it - better not to mix styles.
But my style it definitely ain't - and that's part of it - the reassurance that if I wrote this my way it exits here - which is worth more to me than the (alleged) increase in readability.
|
|
|
|
|
It's an old lesson I learned, probably from the days of assembly -- always have one point of return, mainly for consistent stack cleanup. I do rarely make an exception (to that rule) but usually end up making some other change that removes the if.
If you're doing parameter checking, as in your example, I tend to think it's better to throw an exception -- why should the function that's being called expect anything but valid parameters?
I've seen return sprinkled throughout a function as part of the flow control. I hate that. Sometimes I don't see the return, set the breakpoint at the end of the function, and then have to steps through from the top and realize some moron tossed in an early return. I'd almost rather they use a goto to the return, haha.
Personally, I look at code like that and refactor it into smaller functions that have no if statements, and the flow control occurs in a higher level function that doesn't do anything but call other functions based on conditions of previous functions or the data values. A lot more readable too when you separate out the flow control from the individual activities of each flow.
Latest Article - Slack-Chatting with you rPi
Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny
Artificial intelligence is the only remedy for natural stupidity. - CDP1802
|
|
|
|
|
Marc Clifton wrote: If you're doing parameter checking, as in your example, I tend to think it's better to throw an exception -- why should the function that's being called expect anything but valid parameters? Right on !
«Where is the Life we have lost in living? Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?» T. S. Elliot
|
|
|
|
|
I think there are several issues at play here, the most important is one of consistency. If someone coming behind you can pick up on your style, much of the griping goes by the wayside. I am a strong supporter of early return - range checking arguments and the like. Where you get in to trouble is a 500 line function with nested returns - OR - so many levels of logic (to avoid nested returns) that it's screaming at you to re-factor it....
Charlie Gilley
<italic>Stuck in a dysfunctional matrix from which I must escape...
"Where liberty dwells, there is my country." B. Franklin, 1783
“They who can give up essential liberty to obtain a little temporary safety deserve neither liberty nor safety.” BF, 1759
|
|
|
|
|
Not messy at all. When reading through a method line-by-line
<pre lang="Delphi">
if SomeErrorCondition then
Exit(ErrorCode);
</pre>
is actually pretty darn readable. When debugging, setting one breakpoint at the single return statement and then fiddling which branch of the nested if-statement was taken isn't really easier than putting a breakpoint at every return statement and see which gets hit.
|
|
|
|
|
I think that the Return statement should be dropped in any language,
for example look at Delphi (object pascal) they did not have a return statement until recently it seems. A function had to fill up a variable called Result, and because there was no return statement developers where forced to maintain a clean flow.
This is how it should be everywhere IMHO
|
|
|
|
|
The first person to use the term "clean flow" has the definition right to the term
My experience is that prohibiting return (and continue and break) easily ruins that "clean flow". The clean flow should be for the normal, standard, expected behaviour. If something unexpected occurs, or some special case appears, you should handle it (as far as required) and get out of there! You shouldn't clutter up the rest of the function code with error flags and statuses pertaining to a special condition that was handled much higher up, serving only to skip the rest of the function code. That messes up the rest of the function code.
"Then you should raise an exception", some says. That's just another way of returning prematurely; it does not ensure a single point of exit. Besides, the situation is not necessarity exceptional, it may be simply detecting that there is nothing more to be done. Program flow by exceptions is certainly no clean code flow.
|
|
|
|
|
Not sure what you mean
I never had to uses error flags and statuses for anything like this.
In my experience prohibiting return (and continue and break) never ruined that "clean flow" but always improved it. And without using stuff like ugly flags and statuses.
In our coding guidelines the return is prohibited, and since this was introduced we saw the time needed for maintenance and bugfixing dropped noticable.
And yes, exceptions are not to be used for program flow, that is very true.
|
|
|
|
|
|
I'm not sure which version of ReSharper you're using, but modern versions of Rider (which use ReSharper via IPC) would have recommended an early return with the ?. syntax you're proposing, granting you both the shorter expression and shallower nesting, which is good for readability.
Early returns do make the code easier to grok, if for no other reason than that it looks less like a giant chevron heading off into the distant future.
|
|
|
|
|
IMHO Early returns can simplify code and help remove 'blanket cases' rather than have deep nested logic which can be hard to read at first glance. Ive done this for getting on for 4 decades and it's never hurt me or the code ive written, and as for 'horribly messy code', if it's done right then i disagree
|
|
|
|
|
I like single returns but there are exceptions. Sometimes checking needs to be done at the start of a function. Checking that needs a couple of lines, not a single if . Sometimes there are 2-3 such checks. The single-return-rule would force the entire function to be indented 2-3 extra levels. Multi-return: zero extra levels.
"If we don't change direction, we'll end up where we're going"
|
|
|
|
|
Years ago I was working with people who insisted on single point of return and single loop termination, with no exception whatsoever. Both continue and break out of loops were "forbidden". These were also people who insisted on putting opening and closing braces on separate lines, and always enclose the body of an if in braces, even a single assignment (so the minimum line count for an if statement was four, eight lines for an if/else). In some code, opening and closing braces made up at least a third of the code lines.
I guess that made me stall. I got sick of vading through jungles and fords of little more than braces. Finding the end of a loop, or even a function, required you to leaf through pages by pages of code with minimal information content.
In my first programming course, one basic principle was taught: Always fit a function in a single page, so that you can overview all of it. Obviously, the main message was to choose a suitable abstraction level and factor out common sub-operations, but if an if/else costs you a minimum of eight lines, you can't build much abstraction (for the next level) in a single page!
So I use breaks, continues and returns, to keep the function logic together, not spread over multiple pages / screenfuls. If you immediately see where the loop ends, or you have all the returns on a single page, you will easily manage it. If you like to water out your code with tons of braces and elses and umpteen nesting levels, then you loose control over your returns. But that is exactly what returns and continues and breaks are meant to avoid.
|
|
|
|
|
Forogar wrote: This caused horribly messy code
Nah. Earlier return is both much more readable and more logical too.
More readable: you don't have to skip around when following a given execution path, you just follow it to its return.
More logical: you don't have to keep anything you don't need anymore in mind. When the function is done with it, it's returned and doesn't add to the cognitive load anymore.
The time when single exit point was a 'good practice' was, IIRC, during the structured programming days, as an antidote to goto statements.
Forogar wrote: introduces an execution statement (return) on the same line as the "if" which is bad coding practice
Huh? why? It's only styling. I would avoid having it under the if without brackets, because that's confusing sometimes, but on the same line? No problems.
|
|
|
|
|
I have developed c, C++, C# SW for decades. I believe that when an exception occurs, not only must it identify where and what went wrong, but if possible, how to fix it and who to blame. In a recent conversation, my opposite number who has decades of experience pointed out a way to handle this situation in the complicated code we use. Use a goto statement. It is only used within the body of a method and only to take you to the end of the method. It solves a ton of problems with flow and retaining error information. In my past decades of development, I've only used the goto statement once (gotoxy many times ) I plan to use it much more... ONLY WITHIN A METHOD THOUGH!
|
|
|
|
|
I use 'early' returns only to handle errors (typically input or 'no data' errors that don't merit throwing an exception) where the function is returning some sort of null value or an error code.
|
|
|
|
|
When multiple returns reduce the nesting inside a module they make a lot of sense (as well as making the code more readable in my opinion). This is similar to using the && and || conditionals that only evaluation clauses as needed.
|
|
|
|
|
For me, as a novice, my first concern is can I read and understand the code after a good nights rest.
After I get it running, then look for ways to make it better. Of course VS2017 does a lot for me.
I use inline returns all the time for avoiding null errors when getting data from a DataGridView.
But, for compound conditions it depends on what I am doing and whether they can be easily combined.
As for the final version with the "?" for me that obfuscates what is happening. But, then I am a novice.
In this case I would probably settle on the next to last version.
|
|
|
|
|
i would go ether way for what produces smaller and simpler code.
since this is a trivial example it is difficult to speak in general.
in this case i wouldn't go for No.1 it's against my taste, but No.2, No.3 and No.4 are OK.
No.2 and No.3 seem to have a different philosophy but they do exactly the same thing, imminent return if s == null.
i think No.2 is the way assembly coder would see the situation and No.1 would be how a Pascal programmer sees it. structured style programmers would go for a one exit routine, but sometimes that makes code especially complicated.
|
|
|
|
|
I would argue there is no “one way”. When it makes sense use an early return, then do so. The problem I so often see is both methods are used poorly. Programmers use embedded return statements when they should be throwing and catching errors, or they will have one method which has five different returns (bad). Or they use 5 tier “if” statements which is usually an indication that they may need to refactor code, maybe use function overloading or polymorphic behavior. In my opinion, programming is as much art as it is science, knowing when to apply the rules and when not to.
|
|
|
|
|
One way into a method, one way out (not counting ref and out parameters, which are intuitively obvious).
After 40+ years in software development, my tolerance for lazy programmers that just want to hack up some code and get the minimum done with the least time - is very low.
Some software shops are starting to use an approach I have used for years when I hired developers. Instead of hiring 10 "full stack" developers with an eye to cheap labor, H1-B and other inexperienced programmers cranking out poor code that just barely works for today, they take a different road.
For those 10 positions, they hire 6 experienced software engineers that understand how to code for value engineering, supportability, likely future needs, performance, readability, and meaningful comments. A 7th junior developer is hired who has an attitude and willingness to learn from the senior developers - a person whose character is teachable. No H1-B's.
The end result is better code, faster development cycles, fewer bugs, and lower life cycle cost.
Experienced software engineers understand how incredibly sophomoric it is to have multiple returns.
Now get off my lawn! 
|
|
|
|
|
MSBassSinger wrote: my tolerance for lazy programmers that just want to hack up some code and get the minimum done with the least time - is very low. A very strange ad hominem rationale for a personal prejudice applied to a technical issue.
«Where is the Life we have lost in living? Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?» T. S. Elliot
|
|
|
|
|
Not strange if you make the connection between multiple returns and lazy programming.
Then use that as an example of a broader problem in software engineering today.
After 40 years in the business and Navy Nuc school, such observations are intuitive.
|
|
|
|
|