|
I've written them when developing code that matches a previously designed usage pattern. For instance, the TryParse design pattern returns a Boolean for success/failure and the out parameter receives the parsed data on success.
|
|
|
|
|
Out parameters are useful when you want the same operation to behave differently in various situations. I found them useful in my own binary trees where there are use cases to throw an exception or not throw an exception when a key/value is not there. To me, the real purpose of using Out is to eek out minor performance gains since you don't include any Exception data on the stack.
The real reason that Out is in C# can likely be attributed to support for many different Win32 API calls that return HRESULT as-well-as creating a C-style struct containing information requested by the caller.
if (Object.DividedByZero == true) { Universe.Implode(); }
Meus ratio ex fortis machina. Simplicitatis de formae ac munus. -Foothill, 2016
|
|
|
|
|
--Mr. Obvious
They used to be useful, with a bitter aftertaste.
Now there are better alternatives.
|
|
|
|
|
Words of wisdom
|
|
|
|
|
We could instead have something like this:
(bool success, int parsedValue) = Int32.Parse("123");
But I hear that some do not like tuples.
Latest Article - Code Review - What You Can Learn From a Single Line of Code
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
|
|
|
|
|
But then, don't you have to add a separate if line after that to do the "ok" test? For me, it's clearer to read with a bool return and an out parameter.
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Prior to C# 7, wouldn't you need two lines in both cases?
int value;
if (int.TryParse(someText, out value)) ...
vs:
(bool success, int value) = int.TryParse(someText);
if (success) ...
Of course, C#7 makes the first one cleaner:
if (int.TryParse(someText, out int value)) ...
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Richard Deeming wrote: Of course, C#7 makes the first one cleaner:
if (int.TryParse(someText, out int value)) ...
Exactly.
|
|
|
|
|
Marc Clifton wrote: But I hear that some do not like tuples.
In my case, only because I'd rather use a discriminated union (like F#'s Option or Result ) for the return type...
I know, I know, I'm an outlier...
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
|
|
|
|
|
Tuples are fantastic, been using them in Python for ages.
One morning I shot an elephant in my pajamas. How he got in my pajamas, I don't know.
|
|
|
|
|
IMHO, there are far greater atrocities to deal with than "out" parameters.
|
|
|
|
|
It just avoids the question, though: we can declare any non-pleasing use as "unwise.
a.k.a. "Good: the way I use them."
|
|
|
|
|
peterchen wrote: a.k.a. "Good: the way I use them."
Wrong - they are Good the way I use them
Espen Harlinn
Chief Architect - Powel AS
Projects promoting programming in "natural language" are intrinsically doomed to fail. Edsger W.Dijkstra
|
|
|
|
|
|
Of course - as long as you use them as I say!
|
|
|
|
|
I'm sure there are legitimate uses for "outs" but the place most C# devs have to use them (and the only time that they ever seem to crop up in my code) is for various TryParse() methods, which violate the SRP by both validating and parsing.
To my mind, they really should have been implemented as IsParseable() and Parse().
98.4% of statistics are made up on the spot.
|
|
|
|
|
TryParse returns a bool, because sometimes, you need to know if it parsed correctly or not, but you also need the value that is parsed. So, how "else" would you do that? You could use a Tuple but I actually hate tuples and use them very sparingly.
|
|
|
|
|
I'd kind of hope that we always want to test the return value!
Whilst I don't see it as the crime of the century, TryParse() does do two things (hence its need for an "out" as well as a return value).
As I suggested, it should, strictly speaking, be split into two methods that do one thing each e.g.
bool IsParseable(string)
T Parse(string)
as opposed to:
bool TryParse(string, out T)
The return value does not relate to the entire purpose of the method and aside from not following SOLID principles, this also has an effect on code readability. For a start we have a method with a verbal name and a boolean value - "bool DoSomething()" is inherently misleading, a bool should answer a question not describe an action.
Also, the fact that we tend to be looking for a negative in the return value means that we tend to wind up with a rather inverted logic.
I would suggest that:
if (int.IsParseable(someString))
someProperty = int.Parse(someString);
else
would be much more readable than:
if (!int.TryParse(someString, out someProperty))
98.4% of statistics are made up on the spot.
|
|
|
|
|
if (int.IsParseable(someString))
someProperty = int.Parse(someString);
This could lead an interesting discussion, whether this code can be optimized by JIT-compiler to make a parsing only once. But this is C#, who cares?
|
|
|
|
|
PeejayAdams wrote: if (int.IsParseable(someString))
someProperty = int.Parse(someString);
Not very efficient IMHO.
If one is not going to use TryParse then I would use a tuple via an extension method.
|
|
|
|
|
I'd agree - the IsParsable test has to parse the whole date in order to decide it's valid, so you are repeating the code and throwing away the value you wanted. The only solution to that without tuples (which didn't exist in C# when TryParse was written) was Convert.ToDateTime with a try...catch block or extending DateTime to include a "IsBadDate" option, neither of which appeal to me at all.
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
As pointed out elsewhere, the string does not actually have to be parsed twice as it can be validated with a regular expression.
I agree try ... catches would be hideous as would extending data types to have an isBad flag.
Maybe another option (not available back in the day, either) would be to use nullable types and return null when invalid but that, too, would make for some pretty ugly code with all the casting that would be going on.
I'm not seriously suggesting that they change TryParse, just pointing out that it's a rather ugly construct and it breaks a few rules.
98.4% of statistics are made up on the spot.
|
|
|
|
|
You cannot validate a date properly with a regex: is 29-02-2012 valid? How about 29-02-2013? Or 29-02-1900? How about 29-02-2000?
The answers are: Yes, No, Yes, No - but for different reasons. It's a leap year if the year is divisible by 4, but ... century ends aren't leap years, unless they are a milenium end as well. Try writing a Regex that copes flexibly with that!
You can check a date format with a regex, yes - but actual date validation is required for DateTime parsing, and you can only do that when you have converted the whole date!
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
DateTimes are always going to be a hugely complicated thing and locales have to be taken into account however you approach it - "01/11/2018" in some parts of the world means "11/01/2018" so it isn't simply a case of asking whether "01/11/2018" is a valid string. It couldn't be done in a single regex for that reason - it would require a number of regexes to cover various formats/locales.
It would be a lot of code, granted, but I rather suspect that the existing parsing routine is somewhat complex (and no, I certainly wouldn't volunteer to write it!)
98.4% of statistics are made up on the spot.
|
|
|
|
|
Since many times you can't tell if something is parsable until you actually parse it, splitting TryParse into IsParsable and Parse calls can actually double the amount of work it takes to parse.
|
|
|
|