Why does this (null || !TryParse) conditional result in "use of unassigned local variable"?

The following code results in use of unassigned local variable "numberOfGroups":

int numberOfGroups;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
    numberOfGroups = 10;
}

However, this code works fine (though, ReSharper says the = 10 is redundant):

int numberOfGroups = 10;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
    numberOfGroups = 10;
}

Am I missing something, or is the compiler not liking my ||?

I've narrowed this down to dynamic causing the issues (options was a dynamic variable in my above code). The question still remains, why can't I do this?

This code doesn't compile:

internal class Program
{
    #region Static Methods

    private static void Main(string[] args)
    {
        dynamic myString = args[0];

        int myInt;
        if(myString == null || !int.TryParse(myString, out myInt))
        {
            myInt = 10;
        }

        Console.WriteLine(myInt);
    }

    #endregion
}

However, this code does:

internal class Program
{
    #region Static Methods

    private static void Main(string[] args)
    {
        var myString = args[0]; // var would be string

        int myInt;
        if(myString == null || !int.TryParse(myString, out myInt))
        {
            myInt = 10;
        }

        Console.WriteLine(myInt);
    }

    #endregion
}

I didn't realize dynamic would be a factor in this.


Solution 1:

I am pretty sure this is a compiler bug. Nice find!

Edit: it is not a bug, as Quartermeister demonstrates; dynamic might implement a weird true operator which might cause y to never be initialized.

Here's a minimal repro:

class Program
{
    static bool M(out int x) 
    { 
        x = 123; 
        return true; 
    }
    static int N(dynamic d)
    {
        int y;
        if(d || M(out y))
            y = 10;
        return y; 
    }
}

I see no reason why that should be illegal; if you replace dynamic with bool it compiles just fine.

I'm actually meeting with the C# team tomorrow; I'll mention it to them. Apologies for the error!

Solution 2:

It's possible for the variable to be unassigned if the value of the dynamic expression is of a type with an overloaded true operator.

The || operator will invoke the true operator to decide whether to evaluate the right-hand side, and then the if statement will invoke the true operator to decide whether to evaluate the its body. For a normal bool, these will always return the same result and so exactly one will be evaluated, but for a user-defined operator there is no such guarantee!

Building off of Eric Lippert's repro, here is a short and complete program that demonstrates a case where neither path would be executed and the variable would have its initial value:

using System;

class Program
{
    static bool M(out int x)
    {
        x = 123;
        return true;
    }

    static int N(dynamic d)
    {
        int y = 3;
        if (d || M(out y))
            y = 10;
        return y;
    }

    static void Main(string[] args)
    {
        var result = N(new EvilBool());
        // Prints 3!
        Console.WriteLine(result);
    }
}

class EvilBool
{
    private bool value;

    public static bool operator true(EvilBool b)
    {
        // Return true the first time this is called
        // and false the second time
        b.value = !b.value;
        return b.value;
    }

    public static bool operator false(EvilBool b)
    {
        throw new NotImplementedException();
    }
}