Incorrect compiler error usage of uninitialized variable - c#

I just encountered a case where Visual Studio tells me my code might result in accessing an uninitialized variable, but the rules of boolean logic dictate this isn't possible here.
I simplified the code to visualize the problem, in this case appearing for x:
static void Main(string[] args)
{
IDictionary<String, MyType> dictionary = null;
if (new Random().Next() % 2 == 0)
{
dictionary = new Dictionary<string, MyType>();
dictionary.Add("xyz", MyType.Whatever);
dictionary.Add("abc", MyType.DontCare);
}
var myType = dictionary?.TryGetValue("abc", out var x) ?? false ? x : MyType.None;
}
enum MyType
{
None,
Whatever,
DontCare
}
In case dictionary isn't initialized it's null, thus resulting in ?? evaluating the ternary operator to false. This is the only case where x won't be initialized, but still I get the error message for x in the true case of the ternary operator.
Remarks: Setting parenthesis doesn't change anything, and resolving the ternary operator to a full-fledged if doesn't either.
Is this a known behavior or a bug?
EDIT: Just to clarify, I DO know how to fix the problem. I was just slightly surprised to encounter this error, since the described problem, accessing the uninitialized x, will never happen according to boolean logic.
EDIT: Using a full if doesn't change the problem:
static void Main(string[] args)
{
...
MyType myType;
if (dictionary?.TryGetValue("abc", out var x) ?? false)
{
myType = x; // <-- error still occurs here
}
else
{
myType = MyType.None;
}
}

The problem is the x in this line:
var myType = dictionary?.TryGetValue("abc", out var x) ?? false ? x : MyType.None;
Since you have a null-propagation operator (?.), x will never be assigned when dictionary is null. You have to take out x as a separate variable above the var with a default value.
MyType x = MyType.None;
var myType = dictionary?.TryGetValue("abc", out x) ?? false ? x : MyType.None;
The static compiler just isn't smart enough to figure out the null-propagation operator will cause that expression always to return false (and hence x is never used). Not it just treats the statement as if it can.
As you can see on the C# language Github page, there is an active feature request to let the compiler figure out the outcome of the null-propagation operator.

Related

Local variable might not be initialized before accessing - after calling .TryParse()

I have this piece of code:
var kv = new Dictionary<int, string>() { ... };
var kv30Valid = kv.ContainsKey(30) && int.TryParse(kv[30], out var kv30Value);
myObject.nullableInt = kv30Valid ? (int?)kv30Value : null;
Note: myObject is a POCO class representing a table row, that's why nullable int.
I cannot compile my code because I get compiler error on the last line:
Local variable 'kv30Value' might not be initialized before accessing
In which case can it be unintialized and how to properly handle the case to allow valid code?
I need to populate the myObject properties with values from the kv (if they are present) parsed to their respective values.
Solution:
Moving the condition into TryParse() method solved the problem.
var kv30Valid = int.TryParse(kv.ContainsKey(30) ? kv[30] : null, out var kv30Value);
The definite assignment analyzer has limitations (as it must, yada yada yada halting problem, etc). Although we can look at this code and conclude that it'll only access kv30value if ContainsKey returned true and thus TryParse was called, it's too "separate" for the analyzer to be able to see this.
If this was inside an if block using kv30valid it might be able to see it but even then I'm not sure.
In which case can it be unintialized
When kv.ContainsKey(30) returns false, int.TryParse() isn't called, and kv30Value won't be assigned.
To simplify the issue, you have an unassigned variable:
bool test; // declared, but not assigned
if (test)
{
Console.WriteLine("Test is true");
}
This won't compile, because test is not assigned.
Now a method with an out parameter will definitely assign the variable:
bool test;
Assign(out test);
if (test)
{
Console.WriteLine("Test is true");
}
private static void Assign(out bool foo)
{
foo = true;
}
This will print "Test is true".
Now if you make the assignment conditional:
bool test;
bool condition = DateTime.Now > DateTime.Now;
if (condition)
{
Assign(out test);
}
if (test) { ... }
You'll be back at the compiler error:
CS0165: Use of unassigned local variable test
Because the assignment of test can't be guaranteed by the compiler, so it forbids further use of that variable.
Even if the usage of the variable uses the same condition:
bool test;
bool condition = DateTime.Now > DateTime.Now;
if (condition)
{
Assign(out test);
}
if (condition && test)
{
Console.WriteLine("Test is true");
}
Then still the compiler refuses you to use test.
That's exactly the same as with your && int.TryParse(..., out) code. The right side of the && is conditionally executed, thus the compiler will refuse to let you use the variable that's potentially unassigned.
Regarding the discussion below and the downvote on my answer, if you want to know the why behind all this, see the C# language specification chapter 5.3 Definite assignment. Basically put, you get this error because the compiler does a best effort attempt at statically analyzing whether the variable is assigned.
how to properly handle the case to allow valid code?
Declare it above, and assign it a sensible default value:
int kv30Value = 0;
var kv30Valid = kv.ContainsKey(30) && int.TryParse(kv[30], out kv30Value);
Or simplify the code by moving it into an if, where it'll be definitely assigned:
if (kv.ContainsKey(30) && int.TryParse(kv[30], out var kv30Value))
{
myObject.nullableInt = kv30Value;
}

C# Safe navigation operator - what is actually going on?

I've been following the safe navigation operator feature added in C#6 with some interest. I've been looking forward to it for a while. But I'm finding some different behavior than I expected. I'm realizing I really don't understand how it actually works.
Given this class
class Foo {
public int? Measure;
}
Here's some code using the new operator.
Foo f = new Foo { Measure = 3 };
Console.WriteLine(f?.Measure); // 3
f = new Foo { Measure = null };
Console.WriteLine(f?.Measure); // null
f = null;
Console.WriteLine(f?.Measure); // null
Up to here, everything's working as expected. ?. is accessing members when the left hand side is not null, otherwise returning null. But here things go in a direction I wasn't expecting.
var i = f?.Measure; // i is Nullable<int>
Console.WriteLine(i.HasValue); // false
Console.WriteLine(f?.Measure.HasValue); // null
What?
Why can I get HasValue from i, but not from the same expression I assigned to i? How can HasValue ever be null?
Edit: My real question is about program behavior, not a compilation error. I removed the extra stuff about compilation, and focused this question more narrowly on why two different results are returned by what seems like the same logic.
Let's walk through this logically.
var f = ???;
var i = f?.Measure;
var t = i.HasValue;
We don't know if f is null or not.
If f is null, then the result (i) is null
If f is not null, then the result (i) is an int
Therefore, i is defined as int?, and t is a bool
Now, let's walk through this:
var f = ???;
var i = f?.Measure.HasValue;
If f is null, then the result (i) is null
If f is not null, then the result (i) is Measure.HasValue, which is a bool.
Therefore, i is a bool?.
If f is null, we short-circuit and return null. If it's not, we return the bool result of .HasValue.
Essentially, when using ?. - the return type must be a reference value, or a Nullable<T>, as the expression can short circuit to return null.
var i = f?.Measure; // i is Nullable<int>
Console.WriteLine(i.HasValue); // false
Console.WriteLine(f?.Measure.HasValue); // null
In this case, f is null.
The reason why i.HasValue returned false is because i is of type Nullable<int>. So even when the value of i is null, like in this case, i.HasValue is still accessible.
However, f?.Measure.HasValue immediately returns null after f? is evaluated. Hence the result you see above.
Just to quote Rob's comment:
The main thing to realise is that you're reading and understanding
this: f?.Measure.HasValue as this: (f?.Measure).HasValue, which it's
not.
Nullable<T> is actually a struct and therefore cannot be null, only its Value can, so HasValue will always be accessible.
I ran into this today.
What does the following C# snippet print?
public class NullTests
{
public static void Main(string[] args)
{
object obj = DoIt();
Console.WriteLine(obj?.ToString().NullToNothing());
}
private static object DoIt() => null;
}
public static class Extensions
{
public static string NullToNothing(this string input) => input ?? "nothing";
}
Answer: null.
What does the following Kotlin snippet print?
fun main() {
val obj = doIt()
println(obj?.toString().NullToNothing())
}
fun doIt() = null
fun String?.NullToNothing() = this ?: "nothing"
Answer: "nothing".
Like you, I was expecting the Kotlin behaviour, and it tripped me up for the better part of the day. :(

C# - checking if a variable is initialized

I want to check if a variable is initialized at run time, programmatically. To make the reasons for this less mysterious, please see the following incomplete code:
string s;
if (someCondition) s = someValue;
if (someOtherCondition) s = someOtherValue;
bool sIsUninitialized = /* assign value correctly */;
if (!sIsUninitialized) Console.WriteLine(s) else throw new Exception("Please initialize s.");
And complete the relevant bit.
One hacky solution is to initialize s with a default value:
string s = "zanzibar";
And then check if it changed:
bool sIsUninitialized = s == "zanzibar";
However, what if someValue or someOtherValue happen to be "zanzibar" as well? Then I have a bug. Any better way?
Code won't even compile if the compiler knows a variable hasn't been initialized.
string s;
if (condition) s = "test";
// compiler error here: use of unassigned local variable 's'
if (s == null) Console.Writeline("uninitialized");
In other cases you could use the default keyword if a variable may not have been initialized. For example, in the following case:
class X
{
private string s;
public void Y()
{
Console.WriteLine(s == default(string)); // this evaluates to true
}
}
The documentation states that default(T) will give null for reference types, and 0 for value types. So as pointed out in the comments, this is really just the same as checking for null.
This all obscures the fact that you should really initialize variables, to null or whatever, when they are first declared.
With C# 2.0, you have the Nullable operator that allows you to set an initial value of null for heretofore value types, allowing for such things as:
int? x = null;
if (x.HasValue)
{
Console.WriteLine("Value for x: " + num.Value);
}
Which yields:
"Value for x: Null".
Just assign it null by default, not a string value
Here's one way:
string s;
if (someCondition) { s = someValue; }
else if (someOtherCondition) { s = someOtherValue; }
else { throw new Exception("Please initialize s."); }
Console.WriteLine(s)
This might be preferable for checking if the string is null, because maybe someValue is a method that can sometimes return null. In other words, maybe null is a legitimate value to initialize the string to.
Personally I like this better than an isInitialized flag. Why introduce an extra flag variable unless you have to? I don't think it is more readable.
You can keep a separate flag that indicates that the string has been initialized:
string s = null;
bool init = false;
if (conditionOne) {
s = someValueOne;
init = true;
}
if (conditionTwo) {
s = someValueTwo;
init = true;
}
if (!init) {
...
}
This will take care of situations when s is assigned, including the cases when it is assigned null, empty string, or "zanzibar".
Another solution is to make a static string to denote "uninitialized" value, and use Object.ReferenceEquals instead of == to check if it has changed. However, the bool variable approach expresses your intent a lot more explicitly.
I would agree with Vytalyi that a default value of null should be used when possible, however, not all types (like int) are nullable. You could allocate the variable as a nullable type as explained by David W, but this could break a lot of code in a large codebase due to having to refine the nullable type to its primitive type before access.
This generic method extension should help for those who deal with large codebases where major design decisions were already made by a predecessor:
public static bool IsDefault<T>(this T value)
=> ((object) value == (object) default(T));
If you are staring from scratch, just take advantage of nullable types and initialize it as null; that C# feature was implemented for a reason.
I pick initialization values that can never be used, typical values include String.Empty, null, -1, and a 256 character random string generator .
In general, assign the default to be null or String.Empty. For situations where you cannot use those "empty" values, define a constant to represent your application-specific uninitialized value:
const string UninitializedString = "zanzibar";
Then reference that value whenever you want to initialize or test for initialization:
string foo = UnininitializedString;
if (foo == UninitiaizedString) {
// Do something
}
Remember that strings are immutable constants in C# so there is really only one instance of UninitializedString (which is why the comparison works).

C# IsNullOrZero

This pattern comes up very frequently in my code:
x= x== 0? 1: x;
//or
x= x==null? 1: x;
However it happens that sometimes x is a long expression and I'd have to use intermediate variables. That's just useless boilerplate code. I can cook up a method and call it instead:
Util.IfNullOrZero(x, 1);
But that's just ugly. What is the best way of expressing the pattern? In ruby there is such syntax for when x is nil which gets rid of redundant x's:
x||= 1
I could extend object in a manner
public static class wtf
{
public static T Default<T>(this object o, T d)
{
return o == null ? d : new object[] { o }.Cast<T>().First();
}
}
And then do
object param= null;
int x= param.Default(1);
But that's a bit expensive.
In short how to best make C# do x||= 1 like in ruby?
Update
This is what I cooked up. I'm currently looking for a faster way of using the Template parameter to convert object to T.
public static class MyExtensions
{
public static T d<T>(this object o, T d)
{
return o == null || o.Equals(default(T)) ? d : new object[] { o }.Cast<T>().First();
}
}
In fact the code does three things at once: Casts to default type, checks for default value and also checks for null.
Update 2
return o == null || o.Equals(default(T)) ? d : (T)o; // much simpler and faster
I still think it is a commonality which needs to be included in core language.
Update 3
This is what I finally wrote, taking into account DataTable DBNull types.
public static T d<T>(this object o, T d)
{
return o == null || (o is System.DBNull) || o.Equals(default(T)) ? d : (T)Convert.ChangeType(o, typeof(T));
}
For handling the "==null" case, the null coalesce operator does the trick.
y = x ?? z;
means
if (x == null)
y = z;
else
y = x;
I'm not aware of something that check for both zero and null, writing a method to perform this task might be the best solution. Here it goes:
public static T IsNullOrZero<T>(this T variable, T defaultValue)
{
// defaultValue can't be null, doesn't make sense
if (defaultValue == null) throw new ArgumentException("default value can't be null", "defaultValue");
if (variable == null || variable.Equals(default(T)))
return defaultValue;
return variable;
}
Usage:
x = x.IsNullOrZero(y);
Note: this in fact works on non-numbers too (name might be misleading if dealing with non-numbers... maybe something along the lines of IsNullOrDefault might be a better name).
You can check like
public static bool IsNullOrValue(this int? value, int valueToCheck)
{
return (value??valueToCheck) == valueToCheck;
}
more on here
For checking for null and providing a default value, you can use the ?? operator:
return x ?? new Foo();
That means, if x is null, return new Foo(), else return x. You can use it for reference types and nullable types. For nun-nullable types like int, you still need to explicitly check for 0.
What you want is the Coalesce operator (??), which does just that - if returns the first operand if it's not null, and the second if it is. This will instantiate a new object if the current one is null:
return myObj ?? new MyObject();
Note that the ?? operator works only for classes and reference types, not for ints and other value types that can't be null. There, you'll have to check manually for default, uninitialized values (0 for ints and shorts and stuff, false for bools, and so forth)

Conditional Statements difference

Is there any difference between below two statements
if (null != obj)
and
if (obj != null)
If both treated same which will be preferable?
The first is a Yoda condition. Use it you should not.
The difference here is the code generated. The two will not generate the exact same code, but in practice this will have no bearing on the results or performance of the two statements.
However, if you create your own types, and override the inequality operator, and do a poor job, then it will matter.
Consider this:
public class TestClass
{
...
public static bool operator !=(TestClass left, TestClass right)
{
return !left.Equals(right);
}
}
In this case, if the first argument to the operator is null, ie. if (null != obj), then it will crash with a NullReferenceException.
So to summarize:
The code generated is different
The performance and end results should be the same
Except when you have broken code in the type involved
Now, the reason I think you're asking is that you've seen code from C, which typically had code like this:
if (null == obj)
Note that I switched to equality check here. The reason is that a frequent bug in programs written with old C compilers (these days they tend to catch this problem) would be to switch it around and forget one of the equal characters, ie. this:
if (obj = null)
This assigns null to the variable instead of comparing it. The best way to combat this bug, back then, would be to switch it around, since you can't assign anything to null, it's not a variable. ie. this would fail to compile:
if (null = obj)
No, but the second way is more common and more readable (and more logical in my opinion)
No, there is not. It's exactly the same.
The style null == obj is sometimes just used to prevent the common typo obj = null to not accidently assign null to a variable, but with != there's absolutely no reason to do so.
In .NET it won't actually compile for the typo obj = null.
So the compiler prevents you from accidently doing it.
The Yoda condition comes originally from other languages, where this compiler feature is missing.
They are exactly the same.
Some people prefer to put the null as the first part of the expression to avoid errors like this
if (obj = null) // should be obj == null
But of course this doesn't apply to the != operator, so in your example it's just a difference of style.
First type of statement came from C/C++, where was possible to pass not boolean values to condition verification. E.g. anything not 0 was true, and zero was false:
if (5) { } // true
if (0) { } // false
Sometimes it created problems if you forgot to type one '=' char:
if (x = 5) { } // this was true always and changed x value
if (x == 5) { } // this was true, if x was equal to 5
So, Yoda syntax was used, to receive compiler error in case one '=' was missed:
if (5 = x) { } // this was generating compiler error for absent-minded programmers
if (5 == x) { } // this was true, if x was equal to 5
C# allow only boolean value in conditions, So
if (x = 5) { } // this won't compile
if (x == 5) { } // this is true, if x was equal to 5
What about boolean types?
if (y = true) { }
if (y == true) { }
Well, this is useless code, because you can just write if (y).
Conclusion: Yoda syntax is gone with C/C++ and you do not need to use it anymore.
The use of the first form
if (blah == obj)
stems from the days when compilers would not catch if (obj = blah) i.e. unintentional assignment, unless compile warning level was set to maximum

Categories

Resources