C# unassigned static int results to zero - c#

while experimenting static variables I was amazed to know why the static "int" result to 0 (zero) and non-static result to compile time error.
Consider Case 1
static int i;
static void Main()
{
Console.Write("Value of i = " + i);
Console.ReadKey();
}
the output is
Value of i = 0
Case 2 with removing static
static void Main()
{
int i;
Console.Write("Value of i = " + i);
Console.ReadKey();
}
And the output for this will result to compile time error
Error 1 Use of unassigned local variable 'i'
question here is how do both cases differ i.e first one result to 0 and another get compiler error.

The existing answers all miss something important here, which is where the variable is declared. Is it a class variable or a local variable
In the first scenario
class Program
{
static int i;
static void Main()
{
Console.Write("Value of i = " + i);
Console.ReadKey();
}
}
The variable i is declared as a class variable. Class variables always get initialized, it doesn't matter if it's static or not. If you don't provide a default value, the variable is assigned default, which in the case of int is 0.
On the other hand, in the second example
class Program
{
static void Main()
{
int i;
Console.Write("Value of i = " + i);
Console.ReadKey();
}
}
Variable i is local variable. Unlike class variables, local variables are never initialized with a default value implicitly, but only when you explicitly initialize them. So the compiler error comes not from the variable being static or not, but from the difference in initialization between local and class variables.
The specification shares some more details on that: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/variables, especially sections 9.2 Variable Types and 9.3 Default Values.
The interesting parts are
9.2.2 The initial value of a static variable is the default value (§9.3) of the variable’s type.
9.3.2.2 The initial value of an instance variable of a class is the default value (§9.3) of the variable’s type.
9.2.8 A local variable introduced by a local_variable_declaration is not automatically initialized and thus has no default value. Such a local variable is considered initially unassigned.
9.3: The following categories of variables are automatically initialized to their default values:
Static variables.
Instance variables of class instances.
Array elements.
The underlying reason for this has to do with memory management. When you initialize a class with new() the garbage collector zeros out all bytes on the heap, thus basically defaulting the value of the variable. In case of integers this is 0, for an object reference it would be a null.
Since local variables live on the stack, and the garbage collector doesn't live work on the stack, this guarantee does not exist, so we have explicitly initialize a variable before using it.

by definition of the C# language, types have "default values", which are assigned to them if you don't assign something else. numbers have a default value of 0, boolean - false, reference types - null, and structs - each member by it's type.

Based on my limited understanding, by declaring a variable as static, it becomes existing in memory and is assigned a default value of 0, and does not depend on an instance of the class it is in to exist.
If it is not defined as static, it needs to be initialized within the class(as in, given a value) before it can be used in any logic/math.
Now my confusion comes from being very new, and trying to understand exactly WHY you would choose to do something like this one way, instead of another. Perhaps this is a way to have some values that persist that may be necessary even when the class it is in is not existing, and making everything static would result in ineficient use of memory.

The fundamental reason why you do not get a compilation error for the static scenario is because the compiler has no way to be sure that it is not initialized before being read.
Indeed, a static class member without visibility modifier is internal by default. This means that another class of the same assembly could define it before the Main method is called.
And even if it were private, an external code could still define its value using classes in the System.Reflection namespace.
Whereas, for the local variable case, the compiler is sure that no other code could define the variable between its declaration and its first reading.
Indeed, local variables are not accessible outside their declaration scope to non debugging code.

Related

What does happen when you make a struct without using the new keyword?

What does happen behind the scenes when you make a struct without using the new keyword?
Let's say we have this struct:
struct Person
{
public int Age;
public string Name;
}
And In the Main() method I decide to make an instance of it without the new keyword like that:
Person p;
now if I try to access p.Age I will get a compile-time error saying "Use of possibly unassigned field 'Age'" however if I make an instance of the struct like that:
Person p = new Person();
and then I try to access p.Age I will get the value of 0. Now what exactly happens behind the scenes? Does the Runtime initialize these variables for me or the compiler places code that initializes them in the IL after compilation?
Edit:
Can anybody also explain this behavior:
Code:
struct Person
{
public string Name { get; set; }
}
If I make instance of struct like that:
Person p;
and I initialize the name manually
p.Name = "SomeRandomName"';
I won't be able to use it. The compiler gives an error "Use of an unassigned local variable p" but If I make instance of the struct with the default (parameterless) constructor there isn't such an error.
Members don't have the same rules as locals.
Locals must be explicitly initialised before use. Members are initialised by the runtime to their respective default values.
If you want some more relevant information:
In the internal implementation details (non-contractual!), up to the current MS .NET runtime for Windows objects are allocated in pre-zeroed memory on the heap (when they're on the heap at all, of course). All the default values are "physical" zeroes, so all you need is e.g. "200 consecutive bytes with value 0". In many cases, this is as simple as asking the OS for a pre-zeroed memory page. It's a performance compromise to keep memory safety - you can easily allocate an array of 2000 Person instances by just doing new Person[2000], which just requests 2000 * size of Person bytes with value zero; extremely cheap, while still keeping safe default values. No need to initialise 2000 Person instances, and 2000 int instances and 2000 string instances - they're all zero by default. At the same time, there's no chance you'd get a random value for the string reference that would point to some random place in memory (a very common error in unmanaged code).
The main reason for requiring explicit initialisation of locals is that it prevents stupid programming errors. You should never access an uninitialised value in the first place, and if you need a default value, you should be explicit about it - the default value then gets a meaning, and meanings should be explicit. You'll find that cases where you could use an uninitialised local meaningfully in the first place are pretty rare - you usually either declare the local right where it gets a value, or you need all possible branches to update a pre-declared local anyway. Both make it easier to understand code and avoid silly mistakes.
If you go through the small struct documentation, you can quote:
A struct type is a value type that is typically used to encapsulate small groups of related variables, such as the coordinates of a rectangle or the characteristics of an item in an inventory.
Normally, when you declare in your code these value type like:
int i; // By default it's equal to 0
bool b; // by default it's equal to false.
Or a reference type as:
string s; //By default it's null
The struct you have created is a value type, which by default isn't initialized and you can't access its properties. Therefore, you can't declare it as:
Person p;
Then use it directly.
Hence the error you got:
"Use of possibly unassigned field 'Age'"
Because p is still not initialized.
This also explains your second part of the question:
I won't be able to use it. The compiler gives an error "Use of an unassigned local variable p" but If I make instance of the struct with the default (parameterless) constructor there isn't such an error.
The same reason you couldn't directly assign p.Name = "something" is because p is still not initialized.
You must create a new instance of the struct as
Person p = New Person(); //or Person p = default(Person);
Now, what happens when you create a new instance of your struct without giving values to the struct properties? Each one of them will hold it's default value. Such as the Age = 0 because it's an int type.
Every datatype in .NET has a default value. For all reference types it's null. For the special type string it is also null. For all value types it is something akin to zero. For bool it's false because this is the equivalent to zero.
You can observe the same behaviour when you write a class with member fields. After construction all these fields will have a default value even when none was assigned during construction.
The same is also true when you use a struct as a member. Since a struct cannot be null, it will also be initialized and all its members (again) use their default values.
The difference in compiler output is that the compiler cannot determine if you have initialized the member field through any means. But it can determine if you have set the method variable value before reading it. Technically this wouldn't be necessary but since it reduces programming errors (why would you read a variable you have not written?), the compiler error appears.

Why are non-initialized value types not allowed? [duplicate]

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.

Initially assigned variables

The following two categories of variables are initially assigned:
Instance variables of class instances.
Instance variables of initially assigned struct variables.
Now what does initially assigned struct variables mean?
We're not talking about local variable, right? So we're talking about field variables (in both of these categories) that are used in function member definitions?
Clarifying this would be really appreciated. And thanks in advance!
The following two categories of variables are initially assigned: (1) Instance variables of class instances and (2) Instance variables of initially assigned struct variables. What does "initially assigned struct variables" mean?
It means an initially assigned variable of struct type.
Follow along.
class C
{
public int i;
}
...
C c = new C();
Console.WriteLine(c.i);
c.i is an instance variable of a class, so it is initially assigned.
struct S
{
public int j;
}
class D
{
public S t;
}
...
D d = new D();
Console.WriteLine(d.t.j);
d.t is an instance variable of a class, so it is initially assigned. d.t.j is an instance variable of a struct S, and the variable d.t of type S is initially assigned, therefore d.t.j is also initially assigned.
That is, a field of a struct is initially assigned if the variable that holds the value of the struct is itself initially assigned.
By contrast:
void M()
{
int q;
Console.WriteLine(q); // Error
S u;
Console.WriteLine(u.j); // Error
Neither q nor u are initially assigned; they are not fields of any class. Since u is not initially assigned, u.j is not either.
Make sense now?
Your question is not very clear. But it is correct that a field (instance or static) of a class or struct is always considered assigned. It will have the default value of the type, which is null for reference types and nullable types, and "zero" or something similar to zero for other value types.
In contrast a local variable, that is a variable declared inside a method (or constructor, or accessor, etc.) must be explicitly assigned to before it is used.
In the example:
class Example
{
int field;
void Method()
{
int local;
...
...
}
}
the field is considered assigned automatically and will have the initial value 0, whereas the variable local is unassigned and must be assigned to (later in the same method) before it can be used (even later in the same method).
An unassigned local variable may be passed as an out parameter of a method, though.
EDIT: (after helpful comments)
My answer above gives a pretty precise description for (static and non-static) fields of classes and for static fields of structs. But there was missing something, as the comments pointed out, in case of instance fields of structs.
A struct instance is fully assigned when all its instance fields are fully assigned. Given the following (mutable!!) struct:
struct SomeStruct
{
public int AlphaField;
public int BetaField;
}
then the following is legal:
void M()
{
SomeStruct localSS;
// localSS and its fields are not assigned, and can't be read yet
localSS.AlphaField = 7; // legal
int useA = localSS.AlphaField; // legal, AlphaField is assigned
// localSS and its remaining field BetaField are not assigned
localSS.BetaField = 13;
string useB = localSS.ToString(); // legal, localSS variable is now fully assigned
}
Even if the above example seems crazy (because mutable structs are discouraged by most people), it is still entirely equivalent to what happens inside a user-defined instance constructor of a struct. The C# Specification uses this sentence: The this variable of an instance constructor of a struct behaves exactly the same as an out parameter of the struct type—in particular, this means that the variable must be definitely assigned in every execution path of the instance constructor.
Note that one way for an instance constructor of a struct to assign all fields, is to chain another instance constructor with the : this(...) constructor chaining syntax.
Also note that instance constructors of structs must take parameters. The expression new SomeStruct() (with empty parameter list) is equivalent to default(SomeStruct) and evaluates to the definitely assigned instance of SomeStruct where all fields have their default values.
A class (in C#) is a definition of a reference type. This means that any members of that class are stored as references.
A struct (in C#) is a definition of a value type. Any members of this class are stored as values, not as references.
Reference types are able to be unassigned, because they don't need to be assigned until they're used. Using an unassigned class instance member would result in a runtime error.
Value types need a value to store, because they would not be able to determine their memory space otherwise. Using an unassigned struct member would result in a compile time error.

c# in VS2005: what do the following types default to in C#?

For C# in VS2005, what will be value of variables of the following types if they are simply declared and not assigned to any value? ie. What are their default values?
int
bool
string
char
enum
Here's what default value for each type you've mentioned would be.
int = 0
bool = false
string = null
char = '\0'
enum = 0 //behind the scenes enum is int
Taking this forward, at runtime if you wish to capture default value of any type then you can use default statement in C# and simply call it as following.
//This will print 0 on screen.
Console.WriteLine(default(int));
Generally, this is used in generics for identifying default values of generic type arguments, where the type is only known at runtime.
If they're used locally (i.e. they're not members of a class or struct) they won't have default values. You won't be able to use them until they're assigned a value (unless you explicitly "new them up").
If they're not used locally, they'll default to 0, false, null, and '\0'.
Edit: You've added enum to your list. enums default to a value of 0 because they use an int by default behind the scenes. So whatever enumerate is declared as 0 for the enum (typically the first enumerate, but that's overridable) will be the default. If you don't have a 0 value enumerate for whatever reason, then you'll have an invalid value for your enum as the default value.
Please explain. I am talking about declaring the variables inside the scope of a class or method. – Craig Johnston
I told a little white lie to point out how the compiler works. If you declare a local variable, the compiler will not compile if you try to use it without having first explicitly assigning a value to that variable; that includes null for reference types.
For example:
public void Foo()
{
int bar;
int barPlus5 = bar + 5; // Compiler Error!
}
Technically, bar still has a default value of 0, but because the C# compiler will not allow you to use that default value in a locally scoped variable, a locally scoped variable effectively doesn't have a default value. <Ben Kenobi>So what I told you was true, from a certain point of view.</Ben Kenobi>.
There are exceptions to the rule: out parameters get a pass because the compiler enforces that an out parameter must be assigned by a method before it returns, and you can do int bar = new int(); to get the default value, since that's technically an assignment.
Now, if you declare a variable as a member of a class or a struct such as follows:
public class Foo
{
public int Bar {get;set;}
public Foo() { }
}
And then you instantiate Foo somewhere, Bar will have a default value of 0.
For example:
var foo = new Foo();
Console.WriteLine(foo.Bar); // output: 0
MSDN article - Value Types.
All value types implicitly declare a
public parameterless instance
constructor called the "default
constructor". The default constructor
returns a zero-initialized instance
know as the default value for the
value type.
In case of local variables (Value or
Reference Types) in C#, they must be
initialized before they are used.
MSDN Article - Types
A type that is defined as a class,
delegate, array, or interface is a
reference type. At run time, when you
declare a variable of a reference
type, the variable contains the value
null until you explicitly create an
instance of the object by using the
new operator, or assign it an object
that has been created elsewhere by
using new.

Noninitialized variable in C#

I have the following piece of code:
class Foo
{
public Foo()
{
Bar bar;
if (null == bar)
{
}
}
}
class Bar { }
Code gurus will already see that this gives an error. Bar might not be initialized before the if statement.
What is the value of bar? Shouldn't it be null? Aren't they set to null? (null pointer?)
No, local variables don't have a default value1. They have to be definitely assigned before you read them. This reduces the chance of you using a variable you think you've given a sensible value to, when actually it's got some default value. This can't be done for instance or static variables because you don't know in what order methods will be called.
See section 5.3 of the C# 3.0 spec for more details of definite assignment.
Note that this has nothing to do with this being a reference type variable. This will fail to compile in the same way:
int i;
if (i == 0) // Nope, i isn't definitely assigned
{
}
1 As far as the language is concerned, anyway... clearly the storage location in memory has something in it, but it's irrelevant and implementation-specific. There is one way you can find out what that value is, by creating a method with an out parameter but then using IL to look at the value of that parameter within the method, without having given it another value. The CLR doesn't mind that at all. You can then call that method passing in a not-definitely-assigned variable, and lo and behold you can detect the value - which is likely to be the "all zeroes" value basically.
I suspect that the CLI specification does enforce local variables having a default value - but I'd have to check. Unless you're doing evil things like the above, it shouldn't matter to you in C#.
Fields (variables on classes / structs) are initialized to null/zero/etc. Local variables... well - since (by "definite assignment") you can't access them without assigning there is no sensible way of answering; simply, it isn't defined since it is impossible. I believe they happen to be null/zero/etc (provable by hacking some out code via dynamic IL generation), but that is an implementation detail.
For info, here's some crafy code that shows the value of a formally uninitialised variable:
using System;
using System.Reflection.Emit;
static class Program
{
delegate void Evil<T>(out T value);
static void Main()
{
MakeTheStackFilthy();
Test();
}
static void Test()
{
int i;
DynamicMethod mthd = new DynamicMethod("Evil", null, new Type[] { typeof(int).MakeByRefType()});
mthd.GetILGenerator().Emit(OpCodes.Ret); // just return; no assignments
Evil<int> evil = (Evil<int>)mthd.CreateDelegate(typeof(Evil<int>));
evil(out i);
Console.WriteLine(i);
}
static void MakeTheStackFilthy()
{
DateTime foo = new DateTime();
Bar(ref foo);
Console.WriteLine(foo);
}
static void Bar(ref DateTime foo)
{
foo = foo.AddDays(1);
}
}
The IL just does a "ret" - it never assigns anything.
Local variables do not get assigned a default value. You have to initialize them before you use them. You can explicityly initialize to null though:
public Foo()
{
Bar bar = null;
if (null == bar)
{
}
}
Local variables are not assigned a default value, not even a null.
The value of bar is undefined. There's space allocated for it on the stack, but the space isn't initialised to any value so it contains anything that happened to be there before.
(The local variable might however be optimised to use a register instead of stack space, but it's still undefined.)
The compiler won't let you use the undefined value, it has to be able to determine that the variable is initialised before you can use it.
As a comparison, VB does initialise local variables. While this can be practical sometimes, it can also mean that you unintenionally use a variable before you have given it a meaningful value, and the compiler can't determine if it's what you indended to do or not.
It doesn't matter because no such code should be compilable by any compiler that implements C#.
If there was a default value, then it would be compilable. But there is none for local variables.
Besides "correctness", local variable initialization is also related to the CLR's verification process.
For more details, see my answer to this similar question: Why must local variables have initial values?

Categories