|
Sander Rossel wrote: I really hope professional programmers grasp the concept Been to QA recently?
|
|
|
|
|
Since when do programmers visit QA?
|
|
|
|
|
Well there are at least some who do! Guys like Richard who supply the responses. Most of them qualify
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
I visit QA and try to find questions that I can answer but, for the most part, the senior programmers that haunt these halls give way better answers than I ever could.
if (Object.DividedByZero == true) { Universe.Implode(); }
Meus ratio ex fortis machina. Simplicitatis de formae ac munus. -Foothill, 2016
|
|
|
|
|
Alright, I guess the (sado-)masochistic programmers among us visit QA
|
|
|
|
|
The examples you've posted in reality would probably run asynchronous; in which case, any return values would be via call-backs and classes descended from EventArgs.
It's very hard justifying the use of "out" in an event-driven environment.
In any case, as soon as you need 2 "outs", it starts getting ugly / uglier.
|
|
|
|
|
I do use the out keyword, quite similar to your way of using it.
When looking for an item in a list with some condition, it is normally not an exceptional case when no item meets the condition (hence throwing an Exception is not appropriate). With a bool TryGetItemByCondition(object condition, out SomeType item) , there is no more need to check item for null , thus simplifying the code.
|
|
|
|
|
Thanks for the input. I see that it might be good practice that when I also use out , I should clearly label the functions TrySomething(params, out result) to bring them more in line with established syntax.
if (Object.DividedByZero == true) { Universe.Implode(); }
Meus ratio ex fortis machina. Simplicitatis de formae ac munus. -Foothill, 2016
|
|
|
|
|
I occasionally use the out or ref keyword, but not often at all. Personally, if I need to return more than just some result I create a class. eg. In my DAL component I have a method that executes a given query and returns a Result class instance (Result is a class I wrote, nothing .Net native)
The result class in my case contains:
* The Dataset with the returned results (if any)
* A status enum
* An exception (can be null if everything goes well)
* The executed SQL
That way I have one line of code that executes the statement and one of code that will check wether that went OK or not. Notice that I have for more flexibility in my return object and if I ever need to change it (eg add a property to the Result class) I have a lesser change of high impact on the rest of the code.
in short. out and ref can be useful in some cases, but I would not use it as a rule of thumb.
That's my opinion anyway.
|
|
|
|
|
I've also created a similar class class ,FunctionResult<t>, that used generics to populate the result with an accompanying status enum and an optional exception field. I understand the point that Sander eluded to previously that a Result class add an extra layer of complexity that might cause confusion to other developers if they are not familiar with it or if it is not a standard code practice in your organization.
if (Object.DividedByZero == true) { Universe.Implode(); }
Meus ratio ex fortis machina. Simplicitatis de formae ac munus. -Foothill, 2016
|
|
|
|
|
Sometimes, you need out because any other solution would be unwieldy. For example, look at TryParse and TryParseExact:
public static bool TryParse(string s, out int result) The difference between Convert.ToInt32 and Int32.TryParse is that the former throws an exception, the later returns an OK / Fail result - and needs the out parameter in order to return the value as well.
While you could use Convert instead, and wrap it with a try...catch block to get the same effect, using exceptions as part of normal processing is an anathema to me (and is rather ugly). And user input checking is (or should damn well be) part of normal processing.
You could create a Generic type which contains the value and a bool but that's ugly and annoying as well.
One out or ref for good reason is OK - if it starts to get more than that, then probably it needs a class or struct instead.
And I do find the "using out and ref requires an understanding of pointers" a bit specious as well: if you don't understand them, then I suspect that an out parameter is the least of your problems!
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
|
|
|
|
|
Thank you for the input. I think I am getting a better understanding of when to use
out<\out>. Would you say that a fair example is in functions that accept user inputs and can throw or rethrow several different exceptions of which only a couple represent an actual problem and the rest of them represent errors in the user's input that can be safely swallowed within the function?<br />
<div class="signature">if (Object.DividedByZero == true) { Universe.Implode(); }<br />
Meus ratio ex fortis machina. Simplicitatis de formae ac munus. -Foothill, 2016</div>
|
|
|
|
|
No, the fact that it's user input doesn't matter.
It's that you need to return two values (in this example a good/bad signal and a processed result) where there isn't the option of including a "bad" indication in the result.
For reference types, a "bad" result can be null and anything else is OK - but with value types that isn't possible, and returning a nullable value type is exactly the same (in practice) as returning a special type that contains both results. But with the added complication that it can't be used directly once it's returned!
And throwing exceptions is fine and dandy, but I don't like using them as a part of "normal" processing - they are exceptional events, and have a cost associated (The True Cost of .NET Exceptions — Solution | Rico Mariani's Performance Tidbits[^] describes the situation nicely). Plus the code becomes ugly and tends to get omitted by beginners, so instead of teaching them good practices, they just ask the same old question in QA!
Plus, as Pete said in the thread below mine, returning a bool and an out parameter means that you don't need to pollute the heap with "extra" info, and the bool value doesn't persist.
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
|
|
|
|
|
Ah, makes sense. The article was a good read but, since my knowledge of the exact operation of the CLR is incomplete, I have a question.
Is there a computational difference between these two code blocks?
try
{
}
catch (Exception)
{
return false;
}
try
{
}
catch
{
return false;
}
I am curious if there are certain methods of exception handling that don't unwind the call stack and don't create any additional overhead when the exception occurs. I can see this to be more appropriate in situations where I need the code to just reply, 'Sorry Dave, I'm afraid I can't do that' instead, as exceptions are appearing to be, calling the fire department. In this sense, when iterating through ten million rows in a database that requires you to convert strings to numbers and dates (which is understandably poor design), I would think it would be better to hit the exception and pass over it, possibly flagging it for later remediation, without creating a whole lot of exception overhead so that processing millions of rows could be done in seconds instead of minutes. Am I in the ballpark with this one?
if (Object.DividedByZero == true) { Universe.Implode(); }
Meus ratio ex fortis machina. Simplicitatis de formae ac munus. -Foothill, 2016
|
|
|
|
|
No difference - they both catch all exceptions. And so are both equally bad in most designs - you should only catch exceptions you can deal with: Why catch(Exception)/empty catch is bad | .NET Blog[^]
Try adds an overhead anyway (because it has to put a marker on the stack so the exception throw can "rewind" to it), so adding a try...catch inside a loop is going to extend the processing time for all operations inside the loop, not just the "failures".
And it depends on what exactly you can do about the exception! If it's a "data conversion error" in a row, what you should do about it depends on what exactly you are going to do with the data - there is no "hard and fast rule" that says you should ignore it and continue (logging it for a later fix), or abort the whole run. If you are processing bank transactions then ignoring something very odd is probably not a good idea - but if it's a student grade for an exercise you can probably ignore it (until the end of term, at least).
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
|
|
|
|
|
These are all very good points. The article is a good read, also. If I am putting this all together correctly, peppering your code with try...catch blocks may be acceptable during development to find syntax errors and bugs but the code that goes into to production should be written to handle what exceptions it can or die by fire if it runs into one that it cannot.
Another question, is there a mechanism in the runtime that could respond to an exception without using try...catch?
if (Object.DividedByZero == true) { Universe.Implode(); }
Meus ratio ex fortis machina. Simplicitatis de formae ac munus. -Foothill, 2016
|
|
|
|
|
The short answers are: "no", and "no"!
Production code should be the same as the dev version you are testing - you may well use some more try...catch blocks to get a better idea of why your code fails, but you shouldn't let your app "die in a fire" in production! That's ok for dev, but for prod you will really annoy your users if they type for an hour and then you crash and they lose it! (Think about any Corel product and you'll see what I mean).
It's a balancing act: putting in enough so that you can cope with problems, but not so much that they have an adverse effect on performance.
And there is no mechanism for handling exceptions other than: 1) try...catch, and 2) die in a fire.
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
|
|
|
|
|
I see that I got that point backwards. Sorry, I'm still assimilating a lot of information from the other answers to this question, some of which seem to boil down to personal preference.
I think that I am getting the point. The usage of out is to give the programmer more than one way to approach functions that can/will fail in predetermined ways and to provide the programmer with choices on how to handle them. If one prefers, they can handle an exception from Convert.ToInt32(object) or respond to a false return of Int32.TryParse(object, out int) . Additionally, this can or cannot be applicable given the code's context and task. Still, both methods seem equally fine to me.
if (Object.DividedByZero == true) { Universe.Implode(); }
Meus ratio ex fortis machina. Simplicitatis de formae ac munus. -Foothill, 2016
|
|
|
|
|
Not just that, but yes.
The Exceptions part is just an example - there are load of other cases where you might want to use an out , but they are harder to explain in isolation.
For example, you might want to split out certain values from a collection and return the number of them:
private int GetForSomeReason(List<MyClass> mc, out List<MyClass> result, string somethingToLookFor)
{
... That way, you can chain them together:
int total = GetForSomeReason(myList, out listOfJoes, "joe") + GetForSomeReason(myList, out listOfMikes, "mike"); (I'm not suggesting that that's a good design, just a trivial example of a complicated scenario)
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
|
|
|
|
|
I can see that there are cases when out would make sense when it would save time later in program execution if the same information gathered in one function will be needed by another function in the event that the correct conditions are satisfied.
if (Object.DividedByZero == true) { Universe.Implode(); }
Meus ratio ex fortis machina. Simplicitatis de formae ac munus. -Foothill, 2016
|
|
|
|
|
As in everything else, it really depends what you are trying to solve. I have seen many contorted solutions to avoiding the use of out parameters and whether or not they make sense really depends on what the intent of the code was. Let's take the Try... routines. With later versions of the .NET framework, what could the API designers do? One option is to use a class structure that looks something like this:
public class Parse<T>
{
public bool HasValue;
public T Value;
} This could then be the target of something like this:
Parse<int> value = int.TryParse("12");
if (!value.HasValue) return;
DoSomething(value.Value); While this may seem to be a reasonable solution, on the surface, there are several issues with this design. The biggest problem I have with it is that you are allocating a larger object than you need to. Even if we were to change this to a struct, it's still an unreasonably large surface area for a simple value. Another problem is the cumbersome syntax of having to use value.Value to get the value - you could use implicit operators to work around this but that's adding extra burden again. Granted, the language could be extended with syntactic sugar to hide the underlying implementation (much like null operator hiding the underlying Nullable<T> implementations) but this is, again, overkill because Nullable types were added to support a real problem in the codebase.
So, what other options have I seen? Well, I have seen people returning a tuple with the first parameter being the success or not of the operation. I have seen people advocating the use of exceptions - thereby largely missing the point and I have seen delegates in various forms being required to set values. I have also seen APIs that require multiple calls, the first being a CanParse (or whatever command you need here), followed by a Parse - this being a particularly daft operation because you are effectively calling parse twice - the first one being required to see if you can parse the value, and then the second one being called to get the same value out that you would have got out with the previous operation.
This space for rent
|
|
|
|
|
Pete O'Hanlon wrote: While this may seem to be a reasonable solution, on the surface, there are several issues with this design. The biggest problem I have with it is that you are allocating a larger object than you need to. Even if we were to change this to a struct, it's still an unreasonably large surface area for a simple value.
I'm having some trouble grasping the rationale here, mostly due to the "unreasonably" part. I'm hard-pressed to quantify an extra bit value as unreasonable, especially since it's bundled with a possibly null value and enables an almost English-language null-check mechanism.
After all, the Tuple solution will result in the same memory reservation with the same ubiquitous value access (though I find variable.Item2 less useful than variable.Value).
The exception solution potentially breaks the "don't use exceptions for flow control" rule, which is one of those rules that actually makes objective sense.
I suppose you could use an event driven parser instead, but that introduces even more code overhead.
Now that I think about it, that might be worth working up to add to my library, thanks for the idea!
"There are three kinds of lies: lies, damned lies and statistics."
- Benjamin Disraeli
|
|
|
|
|
It's worth noting that I'm not recommending the Tuple approach either. Basically, what I'm talking about is the fact that you are potentially allocating a class here (if you define this as a class) that will be created on the stack, rather than being on the heap for a reference type. And remember that the boolean return value is going to exist for longer than it needs to if you define your Parse class/struct as a member variable.
This space for rent
|
|
|
|
|
Absolutely understood on the Tuple part. What I saw was what you perceived to be a collection of "bad" ideas.
In terms of cost, though, I've just always seen the intrinsic resilience value of the wrapper class to considerably outweigh the cost of having an extra bit floating around for a GC cycle. Even in aggregate, it would take a massive dataset being processed through a poorly-devised pipeline (after all, how hard is "variable.HasValue ? yield variable.Value : continue"?) in order for that to even show as a blip on the radar.
I suppose I'm mostly curious about a different point of view, mainly how the cost-benefit analysis works
"There are three kinds of lies: lies, damned lies and statistics."
- Benjamin Disraeli
|
|
|
|
|
The key part was my first sentence that it all depends on the context. My point there was that there are times when it's simpler and more appropriate to just return an "out" value, rather than having to contort yourself for the sake of purism. I deliberately focused on the OP's sample because the Try.... don't really need to do much more than they do. Now, suppose we wanted to extend the example, what about if we were looking to answer the question of why did it fail? Then it becomes more appropriate to return a struct/class.
public class Parse<T>
{
bool HasValue { get; set; }
T Value { get; set; }
string AdditionalInformation { get; set; }
}
This space for rent
|
|
|
|
|