Search code examples
c#language-theory

Why is TryParse the way round that it is?


I've been struggling to get my head around a natural way of using TryParse because I keep expecting it to work the other way around (i.e. to return the parsed value and emit the boolean for whether the input parsed).

For example, if we take a basic implementation of Parse, the return value is the parsed input:

int parsedValue = int.Parse(input);

This works fine until it gets a value that it can't parse, at which point it entirely reasonably throws an exception. To me, the option then is either to wrap the parse in something like a try-catch block to handle the exception and a condition to set a default, or just to use TryParse to let C# do all that for me. Except that's not how TryParse works. The above example now looks like this:

bool parseSucceeded = int.TryParse(input, out int parsedValue);

To get it to assign in the same way as Parse, I wrap it in a ternary conditional with parsedValue and a default value (in this case, 0) as the true and false results respectively:

int parsedValue = int.TryParse(input, out parsedValue) ? parsedValue : 0;

But I still feel like I'm missing the point with TryParse if I'm just working around its default behaviour like this. I've read Tim Schmelter's excellent answer in which he shows its internal workings, from which I can suppose that it returns the boolean because it's easier internally than passing it out at all the various places that it currently returns. But I'm not sure about this, and I'm not satisfied that I understand its intent correctly. I also tried reading the documentation for it, but the remarks don't clear up my confusion (I don't think they even make its differences with Parse clear enough, like the change in return type).

Am I understanding it correctly, or am I missing something?


Solution

  • Sure, it could have been implemented as

    int TryParse(string input, out bool succeeded)
    {
    
    }
    

    But as mentioned in a comment, the common use case for the function is:

    string input;
    int parsedValue;
    if(int.TryParse(input, out parsedValue))
    {
        // use parsedValue here
    }
    

    With the signature you propose, that code would now be:

    string input;
    bool succeeded;
    int parsedValue = int.TryParse(input, out succeeded)
    if(succeeded)
    {
        // use parsedValue here
    }
    

    So there's more code for no functional benefit. Also, with your ternary operator, if the parse fails you just set a value of zero, which is unnecessary since the default value of it is 0. You could just do:

    int parsedValue; 
    int.TryParse(input, out parsedValue);
    

    If the parse fails, parsedValue will have a value of 0; (I also question if/how you distinguish between an actual result of 0 and a failed parse, but I'm sure you have a reason).

    So there's no technical reason why the signature is the way it is; it's a design decision that is appropriate for the most common use cases.

    Of course, now with tuples in C# 7 you could have:

    (int parsedValue, bool succeeded) = int.TryParse(input);
    

    but again there's little functional benefit and prevents you from inlining the TryParse in an if statement.