In general, a method's return value as in bool DoSomething()
is the result that is deliberately intended by the programming logic. Put in other words, the return value of a method must represent the purpose of calling that method.
On the other hand, an output out
parameter modifier (there is also a ref
modifier in C#), implies an additional information that is generated during the method execution. This information is not the goal of the method, but still it is necessary to be supplied, because it may be used latter, or because it could be tedious to obtain that information a second time.
For instance, take the bool int.TryParse(string value)
method. It implies that you are interested in checking if value
is an integer, regardless of the actual integer it represents. In other words, you you ask if some string is a number and expect the computer to say: "yes, it is a n integer" or "no, it is not". The out
parameter in this case represents the parsed integer, that is produced only if the parsing was successful.
Consider for instance the following code:
if (int.IsValidInt(value)) // an imaginary method
{
int theInt = int.Parse(value);
}
Assume that the int.IsValidInt(value)
method (that does not originally exist in .NET) checks if a string is integer by internally parsing it. It will produce an integer corresponding to the value
parameter, but we will not be able to use it latter. So, if we need it, we will have to parse it again (via the int.Parse
method), thus repeating the same operations already done by the int.IsValidInt
alongside all the associated CPU and memory usage.
In such cases (like the one determining if a string represents an integer) we may have to produce a secondary result, that should be used latter. This is a good enough reason to use an an output parameter, as done in the int.TryParse
method.
In regards to choosing which to be the return value, I think it should be the one that best represents the intentions of the method, and any additional data should be supplied as an output parameter.
According to the int.Parse
vs. int.TryParse
question, it depends on your case. If you need to to execute different logic depending on the input being a number or not, the int.TryParse
seems more natural to use as it implies the logical branching:
if (int.TryParse(input, out parsed))
{
int importantCalculation = parsed*someMagicNumber;
/// other business logic
}
else
{
// ask for input again
}
In case you need to operate with the input, you have a choice:
Use int.Parse(input);
directly. This will cause an exception if the input is not valid, and you may have to handle the exception using try-catch
blocks. Do this, if you need to show the user information for the error, or if invalid integers are unacceptable in this case.
Use the int.TryParse
in combination with if
-else
. This can be useful if you need faster code (exception slow down the runtime), or if you have an alternative logic flow that can be executed.