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();
}
}