Goal:
I am having some issues in C# when ensuring that a variable retains its assigned value for the duration / runtime of a program. In particular, I am attempting to:
Read a number in from some input
Save it to a variable of type double
Print the variable
Ensure that this value stays the same for the duration of the program, so that on the next iteration when a new value is read in, the previous value from step (2) is still printed.
Attempts:
I have attempted to use a global static variable such as public static double foo;, however, whenever the method that retrievs new values is called again, a new value is printed.
In C, for example, I believe the closest functionality to this would be to use the static keyword, however, I have read that this functionality has been intentionally excluded from C# and I am struggling to learn why this is the case.
void foo()
{
static int j;
int i = calculateSomeValue() + j;
j = i;
}
Please note that before deciding to post this question, I have consulted the following resources:
https://softwareengineering.stackexchange.com/questions/141871/false-friends-keyword-static-in-c-compared-to-c-c-and-java
https://learn.microsoft.com/en-us/answers/questions/240965/retain-previous-value-of-text-box-till-the-form-is.html
Retain local variable across method calls
How to retain old value when setting variable on c# class
https://social.msdn.microsoft.com/Forums/en-US/46243c7b-959e-4753-a173-34f52a7f8922/variables-retain-value-from-first-pass?forum=csharpgeneral
Q1. How can a value assigned to a variable be retained for the entire runtime of a 'C#' program?
Apologies if I am missing something extremely obvious, but it seems that the static keyword in C is used in a different manner compared to that of C#.
According to your description, the variable is re-assigned at step #2.
It is expected that step #3 (Print the variable) will output the changed variable value at each iteration.
Your understanding of "static" meaning in C# is correct, at least in the scope that you have described.
Related
It seems like there is no way to have unassigned local variables in your code or check for them, as the compiler spits out Use of unassigned local variable error.
Why is the compiler not using default(T) on these variables at compile time?
Even if it's harder to do for value types, references types could easily be initialized to null in this case, right?
Here is some test code:
public void Test ( )
{
int x;
string s;
if ( x == 5 )
Console.WriteLine ( 5 );
if ( s != null )
Console.WriteLine ( "s" );
}
which returns:
Use of unassigned local variable 'x'
Use of unassigned local variable 's'
UPDATE:
For people who claims this is not allowed for a good reason, why is it allowed on a class level?
public class C
{
public int X;
public string S;
public void Print ( )
{
Console.WriteLine ( X );
Console.WriteLine ( S );
}
}
This code compiles perfectly fine.
Why is it fine to have on a class level but not on a method level?
I see you've updated your question, so I'll update my answer. Your question has two parts, one relating to local variables and the other to instance variables on a class instance. First, however, this isn't really a compiler design decision, but rather a language design decision.
Spec Section 12.3.1/12.3.2
Local Variables
We know why you can define a variable without giving it a value. One reason, an example of something like this:
int x;
// do stuff
x = 5; // Wow, I can initialize it later!
Console.WriteLine(x);
The standard defines why this is valid code. Now, I'm not on the C# design team, but it makes good sense why they wouldn't automatically initialize the code for you (besides the performance hit when you actually didn't want it to be automatically initialized).
Say the code above was your intention, but you forgot to initialize x = 5;. If the compiler had automatically initialized the variable for you, the code would compile, but it would do nothing like you would expect.
Granted this is a trivial example, but this was a very good design decision from the language designers, as it would save many headaches trying to figure out why something wasn't working as expected.
As a side note, I can't think of a reason why you would want to define the code without assigned something to it, or use the default value (in every case), to me that would likely be a bug, which I'm sure is what the compiler designers may have determined.
Class Instance Variables
Class level members are defined by the standard to be initially assigned. In fact, to be fair, local variables outside those declared in a catch, foreach or using statement are initially unassigned. So really, this is a standards issue, not a compiler issue.
If I were to try and guess why this is the case with regards to instance variables of class instances, I would say it has to do with how the memory is allocated on the heap, since that is where the classes are allocated. When a class is allocated on the heap, all of its members have to be initialized and allocated on the heap with it. It's not just ok to do it in a class member than a local variable, it has to be done this way. They simply cannot be left unassigned.
C# is a "pit of success" language.
This is a design decision, as the language is completely capable of allowing you to use locals that have not been explicitly assigned. However, it is normally true that usage of such variables is erroneous, that a code path has not set a value for some reason. To avoid such errors, the compiler requires that all locals be assigned before being used.
1 Why does the compiler not allow the use of uninitialized variables?
Because preventing that promotes good programming.
2 Why does the compiler allow the use of uninitialized class members?
Because it's not possible to track this with any accuracy.
By taking your suggestion of initializing reference types to null, instead of the current behavior (buggy code causes a compile time error), you'll instead get a runtime error when you dereference an uninitialized variable. Is that really what you want?
Consider the following code:
void blah(IDictionary<int,int> dict)
{
for (int i=0; i<10; i++)
{
if ((i & 11) != 0)
{
int j;
dict.TryGetValue(i, out j);
System.Diagnostics.Debug.Print("{0}",j);
j++;
}
}
}
Suppose that the TryGetValue method of the passed-in implementation of IDictionary<int,int> never actually writes to j [not possible if it's written in C#, but possible if it's written in another language]. What should one expect the code to print?
Nothing in the C# standard requires that j be maintained when code leaves the if statement, but nothing requires that it be reset to zero between loop iterations. Mandating either course of action would impose additional costs in some cases. Rather than doing either, the Standard simply allows that when TryGetValue is called, j may arbitrarily hold zero or the last value it held when it was in scope. Such an approach avoids unnecessary costs, but would be awkward if code were allowed to see the value of j between the time it re-enters scope and the time it is written (the fact that passing an uninitialized variable as an out parameter to code written in another language will expose its value was likely unintentional).
Because what do you want in there? you want x to be zero by default and I want it to be 5...
if they assign 0 to int(s) and all the world starts assuming so, then they will change to -1 at some point and this will break so many applications around the globe.
in VB6 variables were assigned to something by default I think, and it was not as good as it seemed to be.
when you use C#, or C++, you assign the value with what you want, not the compiler for you.
I'm working on doing some refactoring of functions in an existing ASP.NET MVC application, and came across the following small recursive function within a controller. I'm a little new still to C# & .NET, so please bear with me if I get some things wrong.
private int _bl;
[Session]
public void TotalMaterialSubCategories(IEnumerable<Category> materialMasterCats, int i)
{
foreach (var materialMasterCat in materialMasterCats)
{
_bl = _bl + 1;
materialMasterCat.Level = i;
if (materialMasterCat.ChildCategories.Count != 0)
{
TotalMaterialSubCategories(materialMasterCat.ChildCategories.ToList(), i + 1);
if (materialMasterCat.Parent == 0)
{
materialMasterCat.SortOrder = _bl;
_bl = 0;
}
}
}
}
The thing about it that concerned me is this private int _bl statement. Within this class, the only references to this variable are associated with this function.
I thought the line _b1 = _b1 + 1 might not be reliable because it's not manually initialized. Looking into it though, I believe that since it's an int, it cannot be null or left 'uninitialized', so it's getting a default value of 0; corroborated by the MS Docs. The way the recursion looks like it bubbles up makes me think it'll be set back to 0 at the end of this function call as well. Finally, I'm pretty sure each independent web request gets a separate instance of this controller, so it seems like the way this is written, it should function as expected.
However, I just sort of wondered why this would be written like this. Is there a reason that this isn't just a local variable to the function, initialized with 0? Can you rely on local private variables across functions in controllers? Also, are any of my assumptions / determinations incorrect?
The thing about it that concerned me is this private int _bl statement. Within this class, the only references to this variable are associated with this function.
Obviously we can't see all the code, but if I were to believe you that this Field(not variable) is only referenced by this function then I would surmise that either it's left over when other methods may have referenced it and now those methods no longer exist, used it OR it used by a method to maintain state beyond the execution of any single method (event or property).
The way the recursion looks like it bubbles up makes me think it'll be set back to 0 at the end of this function call as well.
It's set to zero before the constructor is called.
Not necessarily. It's only set back to zero after the method ends if (materialMasterCat.Parent == 0) for each instantiation of this class.
Because controllers aren't static classes, each class create has it's own private version of _bl that can only (normally) be access by the class itself (private access modifer).
However, I just sort of wondered why this would be written like this. Is there a reason that this isn't just a local variable to the function, initialized with 0?
Because then when this code ran, all of them would have a value of 1:
materialMasterCat.SortOrder = _bl;
But what's happening is that each time the function is called, it's being incremented because it's exists in the class's scope, not the functions scope.
For Example
Can you rely on local private variables across functions in MVC Controllers?
Private variables are always available until a class is disposed (generally), this time is referred to as the Lifetime of an object.
I believe that since it's an int, it cannot be null or left
'uninitialized', so it's getting a default value of 0; corroborated by
the MS Docs
Try putting the private int _bl; inside of a function as int _bl; and you will see that you get a compile error because you can't perform a _bl = _bl + 1; operation on uninitialized value. So, it doesn't get automatically initialized in scope of a function, but it does get automatically initialized when it's a property of a class instance.
You can read more on when a value gets assigned and when it doesn't here: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/variables This particular case falls to:
An instance variable of a class comes
into existence when a new instance of that class is created, and
ceases to exist when there are no references to that instance and the
instance's destructor (if any) has executed. The initial value of an
instance variable of a class is the default value (Default values) of
the variable's type. For the purpose of definite assignment checking,
an instance variable of a class is considered initially assigned.
In Delphi you can declare a constant in a method and assign it a value in that same method. The idea is that next time you are in this method, the const will still have the same value that you last assigned it.
It looks like this in Delphi :
(I don't have Delphi here so it is untested, sorry about that, but it is enough to demonstrate what I mean)
procedure Form1.test;
const
AssignableConst: Integer = 0;
begin
ShowMessage(AssignableConst);
inc(AssignableConst);
end;
Every time you call the procedure test the messagebox will show the last value + 1
This example is completely useless I know that it is just to show how an assignable const works in Delphi.
Is there an equivalent for this in c# ?
I don't want a solution that involves private variables in the class, it has to stay inside the method.
My question is about scope. Nothing else. I don't care that the value is part of the state of the object. That is not important. What is important is that I need a variable that is only accessible from the scope of a method, nowhere else.
In Delphi this can be done by using an assignable const, so how can I do this in C#?
I don't want a solution that involves private variables in the class, it has to stay inside the method.
But the value is part of the state of the object (or type, for a static method) - so it makes sense for it to be a field declared in the object.
There's no equivalent to this in C#. The best you can do is have a private variable and document that it should only be used from a specific method. (You could write Roslyn-based tests for that if you really want.)
The closest you can get is:
class MyClass
{
static Action CreateCounter()
{
int counter = 0;
return () => {
Show(counter);
counter++;
};
}
Action showAndIncrementCounter = CreateCounter();
public ShowAndIncrementCounter()
{
showAndIncrementCounter();
}
}
But I still recommend the simple solution of using an instance field for the counter and just not accessing it from outside the method.
It seems like there is no way to have unassigned local variables in your code or check for them, as the compiler spits out Use of unassigned local variable error.
Why is the compiler not using default(T) on these variables at compile time?
Even if it's harder to do for value types, references types could easily be initialized to null in this case, right?
Here is some test code:
public void Test ( )
{
int x;
string s;
if ( x == 5 )
Console.WriteLine ( 5 );
if ( s != null )
Console.WriteLine ( "s" );
}
which returns:
Use of unassigned local variable 'x'
Use of unassigned local variable 's'
UPDATE:
For people who claims this is not allowed for a good reason, why is it allowed on a class level?
public class C
{
public int X;
public string S;
public void Print ( )
{
Console.WriteLine ( X );
Console.WriteLine ( S );
}
}
This code compiles perfectly fine.
Why is it fine to have on a class level but not on a method level?
I see you've updated your question, so I'll update my answer. Your question has two parts, one relating to local variables and the other to instance variables on a class instance. First, however, this isn't really a compiler design decision, but rather a language design decision.
Spec Section 12.3.1/12.3.2
Local Variables
We know why you can define a variable without giving it a value. One reason, an example of something like this:
int x;
// do stuff
x = 5; // Wow, I can initialize it later!
Console.WriteLine(x);
The standard defines why this is valid code. Now, I'm not on the C# design team, but it makes good sense why they wouldn't automatically initialize the code for you (besides the performance hit when you actually didn't want it to be automatically initialized).
Say the code above was your intention, but you forgot to initialize x = 5;. If the compiler had automatically initialized the variable for you, the code would compile, but it would do nothing like you would expect.
Granted this is a trivial example, but this was a very good design decision from the language designers, as it would save many headaches trying to figure out why something wasn't working as expected.
As a side note, I can't think of a reason why you would want to define the code without assigned something to it, or use the default value (in every case), to me that would likely be a bug, which I'm sure is what the compiler designers may have determined.
Class Instance Variables
Class level members are defined by the standard to be initially assigned. In fact, to be fair, local variables outside those declared in a catch, foreach or using statement are initially unassigned. So really, this is a standards issue, not a compiler issue.
If I were to try and guess why this is the case with regards to instance variables of class instances, I would say it has to do with how the memory is allocated on the heap, since that is where the classes are allocated. When a class is allocated on the heap, all of its members have to be initialized and allocated on the heap with it. It's not just ok to do it in a class member than a local variable, it has to be done this way. They simply cannot be left unassigned.
C# is a "pit of success" language.
This is a design decision, as the language is completely capable of allowing you to use locals that have not been explicitly assigned. However, it is normally true that usage of such variables is erroneous, that a code path has not set a value for some reason. To avoid such errors, the compiler requires that all locals be assigned before being used.
1 Why does the compiler not allow the use of uninitialized variables?
Because preventing that promotes good programming.
2 Why does the compiler allow the use of uninitialized class members?
Because it's not possible to track this with any accuracy.
By taking your suggestion of initializing reference types to null, instead of the current behavior (buggy code causes a compile time error), you'll instead get a runtime error when you dereference an uninitialized variable. Is that really what you want?
Consider the following code:
void blah(IDictionary<int,int> dict)
{
for (int i=0; i<10; i++)
{
if ((i & 11) != 0)
{
int j;
dict.TryGetValue(i, out j);
System.Diagnostics.Debug.Print("{0}",j);
j++;
}
}
}
Suppose that the TryGetValue method of the passed-in implementation of IDictionary<int,int> never actually writes to j [not possible if it's written in C#, but possible if it's written in another language]. What should one expect the code to print?
Nothing in the C# standard requires that j be maintained when code leaves the if statement, but nothing requires that it be reset to zero between loop iterations. Mandating either course of action would impose additional costs in some cases. Rather than doing either, the Standard simply allows that when TryGetValue is called, j may arbitrarily hold zero or the last value it held when it was in scope. Such an approach avoids unnecessary costs, but would be awkward if code were allowed to see the value of j between the time it re-enters scope and the time it is written (the fact that passing an uninitialized variable as an out parameter to code written in another language will expose its value was likely unintentional).
Because what do you want in there? you want x to be zero by default and I want it to be 5...
if they assign 0 to int(s) and all the world starts assuming so, then they will change to -1 at some point and this will break so many applications around the globe.
in VB6 variables were assigned to something by default I think, and it was not as good as it seemed to be.
when you use C#, or C++, you assign the value with what you want, not the compiler for you.
if variable is not assigned, then it takes the default value at run time.
for example
int A1;
if i will check the value of A1 at runtime it will be 0;
then why at compile time it throws a error of unassigned value;
why CLR don't use to a lot the default value at runtime;
int A1;
int B1 = A1+10;
it should be 11 as the default value of A1 is 0;
there project property where i can check for "assign default values for unassigned variable";
Can anybody tell me where i can find it?
Your statement
if variable is not assigned,then it takes the default value at run time
is only true for member variables in a class.
For local variables inside a function, this is wrong. Local variables inside a function always require initialization.
it should be 11 as the default value of A1 is 0;
This is exactly the reason that the C# compiler won't let you get away with using uninitialized variables. The result would be 10, not 11. After a good 30 years of experience with C and C++, languages that allow you to use uninitialized variables, the C# team decided that this was a major source of bugs and to not allow this in a C# program.
There are lots of little tweaks like this. Another great example is not allowing fall through to another case in a switch statement. Forgetting to write break is such a classic bug. Outlawing these C-isms is rather an excellent idea and a big part of why C# is such a great language. Unless you dislike the idea of a compiler as a police officer.
Fwiw: using an uninitialized variable is permitted in VB.NET.
Default value is true for class members, but not for function locals. Whatever code you put directly into an as[pc]x file, the code generator will put it into a function.
Most of the time this happens is because the variable is an Object and before you can use it you need to Instantiate it.
When you assign a String = "" this is instantiated for you
You are talking about local variables or class level variables ? The rules are different for both. Check our Jon Skeet's reply at this:
Initialization of instance fields vs. local variables
The heap (reference classes) and the constructor for structs zero's the data.
Simple value-types like int, but also references (=pointers) to objects, do not get a default value on the stack. You should always set it. If this was not mandatory, specially with object-pointers, this could be a major security breach, because you are pointing to unknown locations.
Any default value (like 0) would probably be wrong 50% of the time.