My code is the following
int tmpCnt;
if (name == "Dude")
tmpCnt++;
Why is there an error "Use of unassigned local variable tmpCnt"?
I know I didn't explicitly initialize it, but due to Default Value Table a value type is initialized with 0 anyway. The reference also reminds me:
Remember that using uninitialized variables in C# is not allowed.
But why do I have to do it explicitly if it's already done by default? Wouldn't it gain performance if I wouldn't have to do it?
Local variables aren't initialized. You have to manually initialize them.
Members are initialized, for example:
public class X
{
private int _tmpCnt; // This WILL initialize to zero
...
}
But local variables are not:
public static void SomeMethod()
{
int tmpCnt; // This is not initialized and must be assigned before used.
...
}
So your code must be:
int tmpCnt = 0;
if (name == "Dude")
tmpCnt++;
So the long and the short of it is, members are initialized, locals are not. That is why you get the compiler error.
Default assignments apply to class members, but not to local variables. As Eric Lippert explained it in this answer, Microsoft could have initialized locals by default, but they choose not to do it because using an unassigned local is almost certainly a bug.
The following categories of variables are classified as initially unassigned:
Instance variables of initially unassigned struct variables.
Output parameters, including the this variable of struct instance constructors.
Local variables , except those declared in a catch clause or a foreach statement.
The following categories of variables are classified as initially assigned:
Static variables.
Instance variables of class instances.
Instance variables of initially assigned struct variables.
Array elements.
Value parameters.
Reference parameters.
Variables declared in a catch clause or a foreach statement.
Local variables don't have a default value.
They have to be definitely assigned before you use them. It reduces the chance of using a variable you think you've given a sensible value to, when actually it's got some default value.
The default value table only applies to initializing a variable.
Per the linked page, the following two methods of initialization are equivalent...
int x = 0;
int x = new int();
In your code, you merely defined the variable, but never initialized the object.
A very dummy mistake, but you can get this with a class too if you didn't instantiate it.
BankAccount account;
account.addMoney(5);
The above will produce the same error whereas:
class BankAccount
{
int balance = 0;
public void addMoney(int amount)
{
balance += amount;
}
}
Do the following to eliminate the error:
BankAccount account = new BankAccount();
account.addMoney(5);
Local variables are not automatically initialized. That only happens with instance-level variables.
You need to explicitly initialize local variables if you want them to be initialized. In this case, (as the linked documentation explains) either by setting the value of 0 or using the new operator.
The code you've shown does indeed attempt to use the value of the variable tmpCnt before it is initialized to anything, and the compiler rightly warns about it.
See this thread concerning uninitialized bools, but it should answer your question.
Local variables are not initialized unless you call their constructors (new) or assign them a value.
IEnumerable<DateTime?> _getCurrentHolidayList; //this will not initailize
Assign value(_getCurrentHolidayList) inside the loop
foreach (HolidaySummaryList _holidayItem in _holidayDetailsList)
{
if (_holidayItem.CountryId == Countryid)
_getCurrentHolidayList = _holidayItem.Holiday;
}
After your are passing the local varibale to another method like below.
It throw error(use of unassigned variable). eventhough nullable mentioned in time of decalration.
var cancelRescheduleCondition = GetHolidayDays(_item.ServiceDateFrom, _getCurrentHolidayList);
if you mentioned like below, It will not throw any error.
IEnumerable<DateTime?> _getCurrentHolidayList =null;
While value types have default values and can not be null, they also need to be explicitly initialized in order to be used. You can think of these two rules as side by side rules.
Value types can not be null → the compiler guarantees that.
If you ask how, the error message you got is the answer. Once you call their constructors, they got initialized with their default values.
int tmpCnt; // Not accepted
int tmpCnt = new Int(); // Default value applied tmpCnt = 0
Related
My code is the following
int tmpCnt;
if (name == "Dude")
tmpCnt++;
Why is there an error "Use of unassigned local variable tmpCnt"?
I know I didn't explicitly initialize it, but due to Default Value Table a value type is initialized with 0 anyway. The reference also reminds me:
Remember that using uninitialized variables in C# is not allowed.
But why do I have to do it explicitly if it's already done by default? Wouldn't it gain performance if I wouldn't have to do it?
Local variables aren't initialized. You have to manually initialize them.
Members are initialized, for example:
public class X
{
private int _tmpCnt; // This WILL initialize to zero
...
}
But local variables are not:
public static void SomeMethod()
{
int tmpCnt; // This is not initialized and must be assigned before used.
...
}
So your code must be:
int tmpCnt = 0;
if (name == "Dude")
tmpCnt++;
So the long and the short of it is, members are initialized, locals are not. That is why you get the compiler error.
Default assignments apply to class members, but not to local variables. As Eric Lippert explained it in this answer, Microsoft could have initialized locals by default, but they choose not to do it because using an unassigned local is almost certainly a bug.
The following categories of variables are classified as initially unassigned:
Instance variables of initially unassigned struct variables.
Output parameters, including the this variable of struct instance constructors.
Local variables , except those declared in a catch clause or a foreach statement.
The following categories of variables are classified as initially assigned:
Static variables.
Instance variables of class instances.
Instance variables of initially assigned struct variables.
Array elements.
Value parameters.
Reference parameters.
Variables declared in a catch clause or a foreach statement.
Local variables don't have a default value.
They have to be definitely assigned before you use them. It reduces the chance of using a variable you think you've given a sensible value to, when actually it's got some default value.
The default value table only applies to initializing a variable.
Per the linked page, the following two methods of initialization are equivalent...
int x = 0;
int x = new int();
In your code, you merely defined the variable, but never initialized the object.
A very dummy mistake, but you can get this with a class too if you didn't instantiate it.
BankAccount account;
account.addMoney(5);
The above will produce the same error whereas:
class BankAccount
{
int balance = 0;
public void addMoney(int amount)
{
balance += amount;
}
}
Do the following to eliminate the error:
BankAccount account = new BankAccount();
account.addMoney(5);
Local variables are not automatically initialized. That only happens with instance-level variables.
You need to explicitly initialize local variables if you want them to be initialized. In this case, (as the linked documentation explains) either by setting the value of 0 or using the new operator.
The code you've shown does indeed attempt to use the value of the variable tmpCnt before it is initialized to anything, and the compiler rightly warns about it.
See this thread concerning uninitialized bools, but it should answer your question.
Local variables are not initialized unless you call their constructors (new) or assign them a value.
IEnumerable<DateTime?> _getCurrentHolidayList; //this will not initailize
Assign value(_getCurrentHolidayList) inside the loop
foreach (HolidaySummaryList _holidayItem in _holidayDetailsList)
{
if (_holidayItem.CountryId == Countryid)
_getCurrentHolidayList = _holidayItem.Holiday;
}
After your are passing the local varibale to another method like below.
It throw error(use of unassigned variable). eventhough nullable mentioned in time of decalration.
var cancelRescheduleCondition = GetHolidayDays(_item.ServiceDateFrom, _getCurrentHolidayList);
if you mentioned like below, It will not throw any error.
IEnumerable<DateTime?> _getCurrentHolidayList =null;
While value types have default values and can not be null, they also need to be explicitly initialized in order to be used. You can think of these two rules as side by side rules.
Value types can not be null → the compiler guarantees that.
If you ask how, the error message you got is the answer. Once you call their constructors, they got initialized with their default values.
int tmpCnt; // Not accepted
int tmpCnt = new Int(); // Default value applied tmpCnt = 0
A primitive C# value type, for example int is a struct. So, why is int not initialized? There supposed to be default constructor, I think. On the other hand, a custom struct is ok.
In the following code
struct STRCT { }
class Program
{
static void Main(string[] args)
{
STRCT strct;
strct.Equals(8);
strct.GetHashCode();
strct.GetType();
strct.ToString();
int i;
i.Equals(8);
i.GetHashCode();
i.GetType();
i.ToString();
}
}
while first 5 lines of code are ok from the C# compiler view, next 5 lines of code generates compile error:
use of unassigned local variable
Please, explain why? From my point of view both types are structs and shall have the same behavior.
It's a pathological extreme of the rules of Definite Assignment. Specifically:
A struct-type variable is considered definitely assigned if each of its instance variables is considered definitely assigned.
In this case (STRCT strct), the set of instance variables is empty, and so it is true that they've all been definitely assigned.
This is because, unlike the int, your STRCT doesn't contain any fields and therefore doesn't contain anything that could be "unassigned".
Try changing it to:
struct STRCT
{
public int X;
}
Then you'll get the same compile error:
Error CS0165 Use of unassigned local variable
'strct' ConsoleApplication1 D:\Test\CS6\ConsoleApplication1\Program.cs 15
The C# language specification has explicit rules for "Definite Assignment" in section 5.3:
At a given location in the executable code of a function member, a variable is said to be definitely assigned if the compiler can prove, by a particular static flow analysis (§5.3.3), that the variable has been automatically initialized or has been the target of at least one assignment
And then:
A struct-type variable is considered definitely assigned if each of its instance variables is considered definitely assigned.
So from that last rule, if a struct has no instance variables (i.e. fields) then it is considered to be "definitely assigned", and therefore no compile error will be omitted.
It's class Members that are automatically initialized - so if your int was a field or a property in a class, you'd fine.
However, local variables to a method are not initialized and expect you to give them a value.
Your struct variable works ok for the time being, since it contains no members of its own. Once you add
struct STRCT
{
private int a;
}
you'll get an error for it, too.
Structs are value types
Unlike reference types, a value type cannot contain the null value. However, the nullable types feature does allow for value types to be assigned to null.
Each value type has an implicit default constructor that initializes the default value of that type. For information about default values of value types
See - https://msdn.microsoft.com/en-us/library/s1ax56ch.aspx
My code is the following
int tmpCnt;
if (name == "Dude")
tmpCnt++;
Why is there an error "Use of unassigned local variable tmpCnt"?
I know I didn't explicitly initialize it, but due to Default Value Table a value type is initialized with 0 anyway. The reference also reminds me:
Remember that using uninitialized variables in C# is not allowed.
But why do I have to do it explicitly if it's already done by default? Wouldn't it gain performance if I wouldn't have to do it?
Local variables aren't initialized. You have to manually initialize them.
Members are initialized, for example:
public class X
{
private int _tmpCnt; // This WILL initialize to zero
...
}
But local variables are not:
public static void SomeMethod()
{
int tmpCnt; // This is not initialized and must be assigned before used.
...
}
So your code must be:
int tmpCnt = 0;
if (name == "Dude")
tmpCnt++;
So the long and the short of it is, members are initialized, locals are not. That is why you get the compiler error.
Default assignments apply to class members, but not to local variables. As Eric Lippert explained it in this answer, Microsoft could have initialized locals by default, but they choose not to do it because using an unassigned local is almost certainly a bug.
The following categories of variables are classified as initially unassigned:
Instance variables of initially unassigned struct variables.
Output parameters, including the this variable of struct instance constructors.
Local variables , except those declared in a catch clause or a foreach statement.
The following categories of variables are classified as initially assigned:
Static variables.
Instance variables of class instances.
Instance variables of initially assigned struct variables.
Array elements.
Value parameters.
Reference parameters.
Variables declared in a catch clause or a foreach statement.
Local variables don't have a default value.
They have to be definitely assigned before you use them. It reduces the chance of using a variable you think you've given a sensible value to, when actually it's got some default value.
The default value table only applies to initializing a variable.
Per the linked page, the following two methods of initialization are equivalent...
int x = 0;
int x = new int();
In your code, you merely defined the variable, but never initialized the object.
A very dummy mistake, but you can get this with a class too if you didn't instantiate it.
BankAccount account;
account.addMoney(5);
The above will produce the same error whereas:
class BankAccount
{
int balance = 0;
public void addMoney(int amount)
{
balance += amount;
}
}
Do the following to eliminate the error:
BankAccount account = new BankAccount();
account.addMoney(5);
Local variables are not automatically initialized. That only happens with instance-level variables.
You need to explicitly initialize local variables if you want them to be initialized. In this case, (as the linked documentation explains) either by setting the value of 0 or using the new operator.
The code you've shown does indeed attempt to use the value of the variable tmpCnt before it is initialized to anything, and the compiler rightly warns about it.
See this thread concerning uninitialized bools, but it should answer your question.
Local variables are not initialized unless you call their constructors (new) or assign them a value.
IEnumerable<DateTime?> _getCurrentHolidayList; //this will not initailize
Assign value(_getCurrentHolidayList) inside the loop
foreach (HolidaySummaryList _holidayItem in _holidayDetailsList)
{
if (_holidayItem.CountryId == Countryid)
_getCurrentHolidayList = _holidayItem.Holiday;
}
After your are passing the local varibale to another method like below.
It throw error(use of unassigned variable). eventhough nullable mentioned in time of decalration.
var cancelRescheduleCondition = GetHolidayDays(_item.ServiceDateFrom, _getCurrentHolidayList);
if you mentioned like below, It will not throw any error.
IEnumerable<DateTime?> _getCurrentHolidayList =null;
While value types have default values and can not be null, they also need to be explicitly initialized in order to be used. You can think of these two rules as side by side rules.
Value types can not be null → the compiler guarantees that.
If you ask how, the error message you got is the answer. Once you call their constructors, they got initialized with their default values.
int tmpCnt; // Not accepted
int tmpCnt = new Int(); // Default value applied tmpCnt = 0
If you look at next example:
public void TestLocalValuesAssignment()
{
int valueVariable; // = default(int) suits fine
string refType; // null suits fine as well
try
{
valueVariable = 5;
refType = "test";
}
catch (Exception){}
Console.WriteLine("int value is {0}", valueVariable);
Console.WriteLine("String is {0}", refType);
}
you could easily see, that variables valueVariable and refType could be unassigned before their usage in Console.WriteLine(). Compiler tells us about that with errors:
Error 1 Use of unassigned local variable 'valueVariable'
Error 2 Use of unassigned local variable 'refType'
This is a widespread case and there are loads of answers on how to fix that (possible fixes commented).
What I can't understand is why such behavior exists? How here local variables are different from class fields, where last ones get default value if not assigned (null for reference types and correspondent default value for value types)? Maybe there's an example or a corner case that explains why such compiler behavior is chosen?
basically - this is what MS decided.
If you want more you can read here and check Eric Lippert’s Blog
The reason this is illegal in C# is because using an unassigned local has high likelihood of being a bug.
It's described in c# spec:
5.1.7 Local variables
A local variable introduced by a local-variable-declaration is not
automatically initialized and thus has no default value. For the
purpose of definite assignment checking, a local variable introduced
by a local-variable-declaration is considered initially unassigned. A
local-variable-declaration may include a local-variable-initializer,
in which case the variable is considered definitely assigned only
after the initializing expression (§5.3.3.4).
Within the scope of a local variable introduced by a
local-variable-declaration, it is a compile-time error to refer to
that local variable in a textual position that precedes its
local-variable-declarator. If the local variable declaration is
implicit (§8.5.1), it is also an error to refer to the variable within
its local-variable-declarator.
When you do something that appears stupid, like reading from a variable you've never assigned, there are basically two things the compiler can do:
Give you a diagnostic calling your attention to what likely is a mistake.
Do something arbitrary.
Since option #1 helps you find mistakes, it is preferred, especially when the workaround to tell the compiler "No, I mean to use the original default value" is as simple as adding = 0, = null or = default(T).
As for why class members don't work the same way, it's because this can't be checked at compile time (because of the myriad different orders that the different methods could be called). There would be runtime cost of flags whether each member had been assigned, and testing of those flags.
Note that the compiler does enforce the restriction on struct members in a way that's easy to check at compile-time. Namely, each constructor is required to assign every member.
In reality, your code should be fine, but by strict interpretation, there is a code path which can leave your variables unassigned before use. The try block introduces the potential for code within the block to not be executed (if an exception is thrown), but still execute the code beyond the catch (because there is nothing in the catch such as return or throw to prevent the rest of your method from executing if an exception is thrown in the try).
If you are referring to the difference between initializing "struct" fields and initializing class fields, eg:
public class A
{
}
MyMethod()
{
int myInt; // Initialized to zero, yes, but not yet assigned.
// An error to use this before assigning it.
A myA; // defaults to null, which may be a valid initial state, but still unassigned.
// Also an error to use this before assigning it.
A oneMoreA = null; // Same value as default, but at least intention is clear.
A anotherA = new A(); // What is or is not happening in the constructor is a separate issue.
// At least anotherA refers to an actual instance of the class.
I'm familiar with the C# specification, section 5.3 which says that a variable has to be assigned before use.
In C and unmanaged C++ this makes sense as the stack isn't cleared and the memory location used for a pointer could be anywhere (leading to a hard-to-track-down bug).
But I am under the impression that there are not truly "unassigned" values allowed by the runtime. In particular that a reference type that is not initialized will always have a null value, never the value left over from a previous invocation of the method or random value.
Is this correct, or have I been mistakenly assuming that a check for null is sufficient all these years? Can you have truly unintialized variables in C#, or does the CLR take care of this and there's always some value set?
I am under the impression that there are not truly "unassigned" values allowed by the runtime. In particular that a reference type that is not initialized will always have a null value, never the value left over from a previous invocation of the method or random value. Is this correct?
I note that no one has actually answered your question yet.
The answer to the question you actually asked is "sorta".
As others have noted, some variables (array elements, fields, and so on) are classified as being automatically "initially assigned" to their default value (which is null for reference types, zero for numeric types, false for bools, and the natural recursion for user-defined structs).
Some variables are not classified as initially assigned; local variables in particular are not initially assigned. They must be classified by the compiler as "definitely assigned" at all points where their values are used.
Your question then is actually "is a local variable that is classified as not definitely assigned actually initially assigned the same way that a field would be?" And the answer to that question is yes, in practice, the runtime initially assigns all locals.
This has several nice properties. First, you can observe them in the debugger to be in their default state before their first assignment. Second, there is no chance that the garbage collector will be tricked into dereferencing a bad pointer just because there was garbage left on the stack that is now being treated as a managed reference. And so on.
The runtime is permitted to leave the initial state of locals as whatever garbage happened to be there if it can do so safely. But as an implementation detail, it does not ever choose to do so. It zeros out the memory for a local variable aggressively.
The reason then for the rule that locals must be definitely assigned before they are used is not to prevent you from observing the garbage uninitialized state of the local. That is already unobservable because the CLR aggressively clears locals to their default values, the same as it does for fields and array elements. The reason this is illegal in C# is because using an unassigned local has high likelihood of being a bug. We simply make it illegal, and then the compiler prevents you from ever having such a bug.
As far as I'm aware, every type has a designated default value.
As per this document, fields of classes are assigned the default value.
http://msdn.microsoft.com/en-us/library/aa645756(v=vs.71).aspx
This document says that the following always have default values assigned automatically.
Static variables.
Instance variables of class instances.
Instance variables of initially assigned struct variables.
Array elements.
Value parameters.
Reference parameters.
Variables declared in a catch clause or a foreach statement.
http://msdn.microsoft.com/en-us/library/aa691173(v=vs.71).aspx
More information on the actual default values here:
Default values of C# types (C# reference)
It depends on where the variable is declared. Variables declared within a class are automatically initialized using the default value.
object o;
void Method()
{
if (o == null)
{
// This will execute
}
}
Variables declared within a method are not initialized, but when the variable is first used the compiler checks to make sure that it was initialized, so the code will not compile.
void Method()
{
object o;
if (o == null) // Compile error on this line
{
}
}
In particular that a reference type that is not initialized will always have a null value
I think you are mixing up local variables and member variables. Section 5.3 talks specifically about local variables. Unlike member variables that do get defaulted, local variables never default to the null value or anything else: they simply must be assigned before they are first read. Section 5.3 explains the rules that the compiler uses to determine if a local variable has been assigned or not.
There are 3 ways that a variable can be assigned an initial value:
By default -- this happens (for example) if you declare a class variable without assigning an initial value, so the initial value gets default(type) where type is whatever type you declare the variable to be.
With an initializer -- this happens when you declare a variable with an initial value, as in int i = 12;
Any point before its value is retrieved -- this happens (for example) if you have a local variable with no initial value. The compiler ensures that you have no reachable code paths that will read the value of the variable before it is assigned.
At no point will the compiler allow you to read the value of a variable that hasn't been initialized, so you never have to worry about what would happen if you tried.
All primitive data types have default values, so there isn't any need to worry about them.
All reference types are initialized to null values, so if you leave your reference types uninitialized and then call some method or property on that null ref type, you would get a runtime exception which would need to be handled gracefully.
Again, all Nullable types need to be checked for null or default value if they are not initialized as follows:
int? num = null;
if (num.HasValue == true)
{
System.Console.WriteLine("num = " + num.Value);
}
else
{
System.Console.WriteLine("num = Null");
}
//y is set to zero
int y = num.GetValueOrDefault();
// num.Value throws an InvalidOperationException if num.HasValue is false
try
{
y = num.Value;
}
catch (System.InvalidOperationException e)
{
System.Console.WriteLine(e.Message);
}
But, you will not get any compile error if you leave all your variables uninitialized as the compiler won't complain. It's only the run-time you need to worry about.