|
Your function/procedure shouldn't be so long you need to do that ... perhaps you can pull each section into one of its own?
|
|
|
|
|
I agree, they shouldn't. But they are. Unfortunately most of these functions are way too complex to safely refactor.
Nevermind, I didn't want to hijack this thread into a discussion of maintaining old codebases - I just wanted to point out that any codebase may eventually develop into one. In that light, you have a point: if in your function you get to a point where you need multiple top level control statements (loops, branches), that may be an indication you should refactor this into multiple functions with less complexity.
|
|
|
|
|
It depends. There are times when it is necessary to exit as soon as a decision is reached, as I expect the performance of foreach to be O(n). For example, if a function is trying to find the first prime number within an array then you need to exit as soon as the condition is true, otherwise much time may be wasted. In the example given it depends how large I expect the string array to be, clearly the function itself can potentially take a string array of any size so method 1 seems preferable to me. However, if you don't like multiple return points then use 'break'. A more complex function is often clearer to read and debug if there is only one return point, and this is preferable if speed is not an issue. For example, if a function decides which way a bug is going to turn - left or right, then it may test many conditions, none of which may involve operations on large collections. In this example, it is probably preferable to have only a single return point.
|
|
|
|
|
|
If I were trying to determine if "ABC" exists in values then Code1.
If I were trying to determine if the last element in values (s) was equal to "ABC" then Code2.
I subscribe to early returns. Unless there is a reason to tenderize the value(s) before returning it.
|
|
|
|
|
Both and neither, i usually use what makes more sense in the task at hand, if the method is trivial or requires final cleanup, I prefer a single return point, if depending of a condition the code will run a lengthy or expensive task then I prefer early return.
|
|
|
|
|
One way in, one way out and we stop when we find the value we want.
Boolean DoSomething(string[] values)
{
bool bResult = false;
int i = 0;
while ( (!bResult) && (i < values.GetLength()) )
{
bResult = (values[i++] == "ABC");
}
return bResult;
}
OR
Boolean DoSomething(string[] values)
{
bool bResult = false;
int i = values.GetLength();
while ( !bResult && i )
{
bResult = (values[--i] == "ABC");
}
return bResult;
}
Just realized with the my second one, if the array is empty it still works. The first one does too but I like the second better and will try using that logic from now on. Thanks for making me think.
M__k T J.hnnnnn
What my signature looks like in courier.
modified 26-Jul-13 11:11am.
|
|
|
|
|
I refuse to hire anyone who subscribes to that inane single exit nonsense.
|
|
|
|
|
Oh, you must be lots of fun to work with.
The "correct code"? The "correct code" is something that is easy to maintain and produces the desired result.
In addition your comment does not address the original question. Which is better, multiple returns or a single return? As a maintenance programmer, I fully support a single return statement. Multiple returns are lazy and prone to creating code that doesn't get tested before getting sent to QA.
Granted the example was trivial but the underlying question was not.
|
|
|
|
|
The code you posted with a complex condition and the loop variable incremented inside the assignment is much less readable than returning from inside the loop to me and, I suspect, most people.
|
|
|
|
|
I'm a pleasure to work with because I know my craft and I write readable, maintainable code, not the kind of garbage that was posted here ... a result of a) harebrained adherence to a pointless single-return dogma and b) not being familiar the available tools, such as LINQ, and not being familiar with the state of the art, which now includes the sort of functional programming that LINQ represents. Functional programming is the ultimate in "single return", because there are no return statements, there are just functions that yield expressions. But if you're writing crufty imperative code, single return is bad because a) several empirical studies show that it has high cognitive load, making it difficult to interpret and subsequently more likely have bugs in the original and more likely to be broken when changed, and b) it results in the Arrow Anti-Pattern (http://www.codinghorror.com/blog/2006/01/flattening-arrow-code.html).
Multiple returns are lazy and prone to creating code that doesn't get tested before getting sent to QA.
Oh, you must be a joy to work with as you dishonestly defend positions by making up BS arguments. Laziness and failing to unit test has nothing whatsoever to do with single vs. multiple returns (but it does have a lot to do with people who don't read the literature and so know nothing about the technology of software construction). Multiple returns in guard clauses as mentioned at codinghorror are not "lazy", they are orderly and logical. It's not laziness that leads good programmers to avoid unnecessary structure and condition variables, it's competence.
|
|
|
|
|
At the risk of further baiting the troll, man you take this stuff WAY to seriously. "Garbage"? "Harebrained adherence"? "Not being familiar with the state of the art"? "But if you're writing crufty imperative code"? Dude, you need to get out more, seek some kind of relaxation therapy because you are headed for a coronary if you don't find an outlet for your anger.
Did I insult you? Maybe with the "joy to work with" comment, but really, your first statement was "I would never hire anyone . . ." Someone asked a question that related to opinion. I responded with my opinion, which is just as valid as every other opinion that has been posted in response to the original question.
Heaven forbid I assume anything about you but, how much maintenance programming have you done in your career. Real maintenance programming of a system you didn't start but was hired on well after version 1 or even 2 had shipped? In that world, you play with the hand you are dealt, and on more occasions than I care to remember I have had to deal with code that had NOT been tested before being sent to QA because the programmer just threw in multiple return statements because they ASSUMED they knew how the user would interact with the system. Code goes to the field and the user does something different than what the programmer thought the user would do and BOOM goes the code. The else condition was never tested because the programmer only tested with "good" entries.
It is a mistake we ALL make. We make this mistake because we write the code and know what it SHOULD do and get locked into the mindset that "the user will only try to enter the correct information like I have been testing because that what makes the code work and produce the result the users want." Negative testing and single exits can simplify the maintenance of the code long after the original developer has moved on.
You don't have the luxury of rewriting every module you come across to meet your coding standard, you have time to fix the bug and move on to the next one, after of course you thoroughly test your changes and make sure the changes you made didn't break something else. That something else might not even be in the file you are modifying.
So in conclusion, jibalt, you will find over time that life is too short to worry about this stuff and code is just code. Write it so others can see what is going on because in 6 months from now you will have a hard time remembering why you did what you did when you look back at something you thought was so elegant. That is competence AND experience talking.
Mark T Johnson
Old School Programming
K.I.S.S. because you will probably be the S. who has to go back into that file and fix something.
|
|
|
|
|
|
I debated last night when I saw your comment. Should I respond to this person who waited 5 months to flame me over a lengthy post about life being too short?
Then my curiosity got the better of me and I decided I had to find out why.
So, why, jibalt, why did it take you 5 months to respond to my post? Why after 5 months were you compelled to once again call me a pathetic hypocrite? Every post you have made towards me in this thread has been filled with venom and vitriol. What is it about me that brings out that much anger from you?
5 months. Sounds about right for a jail sentence. Is that where you've been? I can see you having road rage or being in a bar fight or beating up your significant other.
Oh, my blood pressure was quite normal when I wrote that last post. Because you see, I enjoy poking the troll.
|
|
|
|
|
I refuse to hire anyone who subscribes to that inane single exit nonsense. And that code is awful for other reasons too. The correct code is
return values.Any(s => s == "ABC") unless it can be proved to be a performance bottleneck.
|
|
|
|
|
That may be OK for C#; but how does it translate to other languages?
|
|
|
|
|
Modern languages these days have similar functional facilities ... this includes C++11, and even Java finally in Java 8. Others are Ruby, Python (although limited to one line), Scala, Haskell, Clojure of course ...
|
|
|
|
|
I prefer #3 offered by "NeverJustHere":
return values.Contains("ABC");
Each will get the same result, except #2 wastes unnecessary cycles. #3 is best because it is the most efficient, uses the least about of your code, and is already debugged (hopefully MS did their job).
The example in #2 can be made more efficient if you change it to:
Boolean DoSomething(string[] values)
{
bool retValue = false;
foreach (string s in values)
if (s == "ABC")
{
retValue=true;
break;
}
return retValue;
}
-- modified 27-Jul-13 0:03am.
|
|
|
|
|
It's tragic that anyone would ask this, since the second chunk of code is so clearly inferior.
But I would of course write
return values.Any(s => s == "ABC")
|
|
|
|
|
You have posted in the wrong place. The guidelines say no programming questions . This forum is purely for amusement and discussions on code snippets. All actual programming questions will be removed.
|
|
|
|
|
We had this discussion quite recently.
In the example you posted, the second is objectively worse because it doesn't leave the loop at the first opportunity. If you are going to go for a single return point, you must put a break in there.
C# provides a simple way to do this general action of 'find the first that matches a condition': the Linq extension method Contains. If this code is C# 3.5 or later then you should use that: return values.Contains(s => s == "ABC"). Note that you can use this for any construction of this type.
If you're in an environment where you can't do that, I'd pick the first. As soon as you have control structures you can't assume top-to-bottom flow anyway, and you have to track execution paths to follow the code, so there's no good argument for not using return any more.
|
|
|
|
|
Obviously you missed a break in your 2nd method (or I hope so). If you do this, it's actually a hybrid between the 2 methods. A more "strictly" no-goto (even hidden as a break / premature return) would be as per MarkTJohnson's code samples - i.e. add a check in the loop's conditions to see if the state variable has changed.
As for those advocating premature returns, but (in the same breath) dissing goto: Such a return is very related to a goto, as is a break inside a loop. All 3 result in much the same assembly code, the only difference is return/break is safer to use than goto - since goto has more freedom to screw-up. It would be similar in stating that you should always use typed pointers, very true - but it's not as if an untyped pointer is actually "that" different, just possible to do more damage. Not to say that goto's should be used, just to point out that you're walking a fine line between a good idea and contradicting yourself.
Also I'll give you the benefit of the doubt and not try to encourage to use the Contains (or other similar stuff) instead of the entire function, as some have already pointed out. With the thinking that you used this as a sample to make a point, not a sample to take literally.
That said, I tend to find making the 2nd method work properly and efficiently becomes more code. And with more complex functions the extra code becomes exponentially more. Although I don't have trouble reading the principle itself (either one, as long as formatted so the state-set or returns are clearly highlighted, e.g. a blank line after each), I tend to try and write less code (if possible) - so I'd probably go with method 1 if no other reasons are apparent.
This particular thing (i.e. premature return vs state variable) I see as subjective in the same sense that some would like / understand recursive more than iterative loops (or visa versa). If all else is the same - i.e. no need for other stuff to happen too just before the return.
Where it does become a pain, is if your function is later extended. You might later add a further portion which should run even if the value is already found. Perhaps some side effect, like counting how many times a positive was returned through the object's life (sorry - stupid example, but it happens).
|
|
|
|
|
"As for those advocating premature returns, but (in the same breath) dissing goto: Such a return is very related to a goto, as is a break inside a loop."
No it isn't ... goto's are unstructured. This is programming technology and history 101 ... actually .001 ...
"All 3 result in much the same assembly code"
Irrelevant, and not true, or not predictably true.
|
|
|
|
|
Second method if security is a concern (methods like that are not vulnerable to timing attacks[^]); first in all other cases (the first method will always execute in N time, the second is O(N)).
He who asks a question is a fool for five minutes. He who does not ask a question remains a fool forever. [Chinese Proverb]
Jonathan C Dickinson (C# Software Engineer)
|
|
|
|
|
the first method will always execute in N time, the second is O(N)
There is no such thing as "N time". They're both O(N), but the average time for the first one is half that of the second one.
|
|
|
|
|