Search code examples
c#.netparsing

Use of uninitialized variable - the compiler is broken


Obviously the title is somewhat tongue in cheek, but I've checked and double checked and I can't see the error in my logic.

The compiler complains that variable parsed might not be initialized in the return statement. I don't agree. Which of us is wrong, and why?

public DateTime? Test(string nextDate)
{
    DateTime parsed;

    if (nextDate != "TBC" && !DateTime.TryParse(nextDate, out parsed))
    {
        throw new Exception();
    }

    if (nextDate == "TBC")
        return null;

    return parsed;
}

Solution

  • No, the compiler isn't broken at all.

    The compiler isn't meant to be able to tell that

    if (nextDate != "TBC")
    

    and

    if (nextDate == "TBC")
    

    are mutually exclusive. It doesn't try to make any connection between the two conditions. So it can't tell that you'll definitely have called DateTime.TryParse(nextDate, out parsed) if you get as far as return parsed;.

    Basically, the compiler follows relatively simple rules to determine definite assignment (and reachability). Simple rules are easy to reason about, easy to implement, and easy to code to.

    Fortunately, you can make your code simpler and make it compile at the same time:

    public DateTime? Test(string nextDate)
    {
        if (nextDate == "TBC")
        {
            return null;
        }
    
        DateTime parsed;    
        if (!DateTime.TryParse(nextDate, out parsed))
        {
            throw new Exception();
        }
        return parsed;
    }
    

    Now we're dealing with the "special case" of "TBD" in one place right at the start - and then we can ignore that special case for the rest of the code and call TryParse unconditionally, leaving parsed definitely-assigned.