Use of unassigned local variable error is incorrectly indicated by compiler [duplicate]
Asked Answered
C

1

6

Given this code:

private void TryIt(Dictionary<int, int> myDict)
{
    if (myDict?.TryGetValue(1, out int myValue) ?? false)
    {
        Console.Out.WriteLine(myValue); // <-- Error CS0165
    }
}

The c# compiler emits:

error CS0165: Use of unassigned local variable 'myValue'

But it is clearly not possible to reference myValue when the call to TryGetValue() is skipped by the ?. operator. This is because the resulting null is converted to false by ?? false.

In other words, if myDict is null, the ?. operator will skip the call to TryGetValue(), leaving myValue unassigned. I get that.

BUT the ?? operator will then always evaluate that null propagation to false, preventing entry into the if-block in this case.

This is evident at compile-time, so why the error?

I suspect that it probably has to do with how all this syntactic sugar is eventually unwound into actual .NET p-code, but it still seems wrong to error out...

When not using the .? operator, I get no error, which is expected:

    if (myDict.TryGetValue(1, out int myValue))
    {
        Console.Out.WriteLine(myValue); // <-- NO ERROR
    }

It's just when I use .? with ?? false.

Conventual answered 10/4, 2019 at 22:26 Comment(1)
The error message is not incorrect according to the C# language specification. It is literally impossible for the compiler to correctly evaluate execution flow 100% of the time, so there are necessarily limits. For practical reasons, those limits are fairly narrow and exclude the scenario that you want to work. See marked duplicates. The first is exactly the scenario you're asking about, and you should have found it yourself rather than ask a new question. The second addresses the same basic issue more generally (i.e. non-constant if expression makes for reachable if body)Labyrinthodont
D
2

"But it is clearly not possible ..."

That is correct but the compiler does not track the logic that deeply.

The compiler could have deduced this, but note that the scope of myValue extends beyond the if statement:

if (myDict?.TryGetValue(1, out int myValue) ?? false)
{
    Console.Out.WriteLine(myValue); // <-- Error CS0165
}
Console.Out.WriteLine(myValue); // myValue is in scope here

So while you might desire that the compiler figured out all the ?. and ?? logic, and that the code inside the if () { ... } is a special case, that apparently is a feature that wasn't deemed important enough.

myDict?.TryGetValue(1, out int myValue) does not always assign to myValue.

Diatomite answered 10/4, 2019 at 22:44 Comment(2)
I'm trying to figure out what the intent of ` ?? false ` would be, as TryGetValue returns bool. I suspect the intent was closer to ` if (myDict?.TryGetValue(1, out int myValue) ? true : false )` but... Maybe I'm missing somethingAeroscope
"as .TryGetValue() returns bool" - Yes, but ?.TryGetValue() might return bool or null so it becomes bool?Diatomite

© 2022 - 2024 — McMap. All rights reserved.