Scope clashes for fields & local variables - c#

See below code snippets
class scopes
{
static int j=20;
Console.WriteLine(j);
public static void Main()
{
int j=30;
Console.WriteLine(j);
return;
}
}
For above code , variable hiding is supported
see below code
public static int Main()
{
int j = 20;
for (int i=0; i < 10; i++)
{
int j = 30; //can't do this
Console.WriteLine(j + i);
}
return 0;
}
Here for above code variable hiding is not supported.
What is the reason behind this?

In the first case, there is at least a defined way to disambiguate between the two things, i.e. the this. prefix - inside the method, this.j is the field, where-as j is the member. As for why this is supported: speculation, but probably so that adding a field to the class (which could be in a different code file in the case of partial classes) doesn't cause random methods to start throwing compiler errors. Note that the meaning in of j in the method is identical before and after the field j is added.
In the second case, this is not a concern: adding locals can only impact the single local method, and there is no disambiguation syntax (i.e. which j do we mean), and no risk of accidental breakage from unrelated code.

Related

How to solve Identifer Expected problem in C# unity?

Here is my code in which the identifier problem causes.
for (int i = 0; i < buttons.Length; i++)
{
Text[] = buttons[i].GetComponentsInChildren<Text>();
}
Unknown identifier: This type of error could mean that Unity does not know the variable that you are referring to and it is expecting an Identifier.
This might be due to these reasons:
The name of the variable that you are using is incorrect.
The variable has not been declared yet.
The variable has been declared but outside the scope of the method.
Note: The names of all variables and functions are case-sensitive, just using an incorrect case, will assume that you're referring to another variable.
Try this:
for (int i = 0; i < buttons.Length; i++)
{
Text[] texts = buttons[i].GetComponentsInChildren<Text>();
}
You can refer these links link-1 link-2

Scope of a 'for' loop at declaration of a variable

I faced this strange behavior when I was coding. So I ask it here.
What is the scope of a for loop when declaring variables?
This code compiles fine
for (int i = 0; i < 10; i++) { }
for (int i = 0; i < 10; i++) { }
This means both int i are not in same scope.
But this code does not compile.
for (int i = 0; i < 10; i++) { }
int i; // Conflicts with both first loop and second one.
for (int i = 0; i < 10; i++) { }
This means the int i in middle of loops has the same scope of first loop and the second loop.
But how can int i in two for loops have different scope, but the same scope with middle int i? Because currently I see them at the same level.
I know the second code does not compile. Why does the first code compile then if there is problem in scopes. Is this an exception inside the compiler?
The C# compiler does not check whether a variable was declared before or after another variable. All that matters is the scope. The i variable declared between loops surely conflicts with the second loop, because if you use i inside the loop, there is no way to distinguish which i you'd like to use. As for the first loop, an error is still shown, because the block where i is declared encapsulates also the first loop.
For example, the following will not compile, even though j is not visible outside inner braces, so there should not be any ambiguity regarding i:
{
{
int i = 1;
int j = 1;
}
int i = 0; // compiler error: A local variable i cannot be declared in this scope (...)
// j is not visible here
}
Edit regarding the comment:
Why is the following fine?
{
for(int i = 1; i < 10; i++) {}
for(int i = 1; i < 10; i++) {}
}
When you declare a for loop variable, it is visible only inside the loop block. That means that the scopes of both variables are disjoint, since there is no line of code where one block "overlaps" the other one.
The scope of a for loop, for(INIT; COND; INCR) { BLOCK } is identical in scoping to
{
INIT;
while (COND) {
BLOCK;
INCR;
}
}
Thus a for loop can be best thought of as two nested scopes. (Note: the above conversion from for to while does not properly capture the behavior of continue. However, this question is not focused on that)
The issue you run into with the int i outside of the for loop is something called "shadowing." In C++, if you declared a scoped variable with the same name as something in an outer scope, you "shadowed it," silently covering it up until the scope ended. When they developed C#, they felt this was too counterintuitive, and too error prone. In C# it is a syntax error to shadow a variable from an outer scope. By introducing int i to the outer scope, it is now illegal for the for loops to introduce it themselves.
The variable declared in for loop has just scope inside for loop block, but when you declare a variable outside for loop, you cannot have same name variable inside the for loop, because it confuses compiler that which variable you mean in for loop body.
Like i will take your code as example:
int i =0;
for (int i = 0; i < 10; i++)
{
i = i+1; // now compiler is confused which i you mean here, so i complains on compile time that you have two with same name
}
So if you declare it between loops as you did, variable i has scope in both for loops so it is accessible in both for loops, so if you remove first loop it will still complain because of global scope of variable outside the loop:
for (int i = 0; i < 10; i++)
{
i = i+1; // now compiler is still confused which i you mean
}
int i =0;
I don't think it matters where you put int i;.
The compiler first scans the field, after which it starts scanning for expressions. It doesn't compile because the i is already recognized as a field.
There is nothing strange going on. In the second case you've defined an outer i and then try to redefine it in each loop.
Variables declared in a for statement are local to the loop, but you've already defined another variable with the same name in the outer scope.
I think you've already asked another scoping question assuming that the scope of a variable starts from the point of declaration ?
A variable's scope is the block in which it is defined, it isn't affected by its placement. While the compiler will refuse to use the variable before the declaration, it is still in scope
int i; You declare outside the loop is available for the current function. Either declare only outer int i, and remove int i from both loops, or just remove this outer variable.

Using Volatile keyword in C#

I am using the Volatile keyword, but it is behaving someway different than expected.
Here's my code
private static volatile int _N = 0;
var up = Task.Run(() =>
{
for (int i = 0; i < 1000000; i++)
_N++;
});
for (int i = 0; i < 1000000; i++)
_N--;
up.Wait();
Console.WriteLine(_N);
_N is a class variable.
What I get is a different number every time, as if the keyword volatile were not used.
Is it the right behaviour of the keyword?
What I get is a different number every time, as if the keyword volatile were not used. Is it the right behaviour of the keyword?
Specifying the variable as volatile doesn't make either the increment or decrement operation atomic. Imagine that your loop had been written like this:
for (int i = 0; i < 1000000; i++)
{
int x = _N;
x++;
_N = x;
}
That's effectively what the previous loop was - it's just that now it's clearer that you're reading, then performing an operation, then writing. There's nothing to stop another thread from writing a different value between those two operations.
For atomicity, you should use Interlocked.Increment and Interlocked.Decrement.
Personally I would try to avoid using volatile wherever possible. The exact meaning of it is relatively hard to describe, and hard to reason about in my view. It's better to use higher level constructs where possible.

Why for loop want take parameters of function in c#?

Why this code doesn't work?
private void Function(int starts , int ends)
{
int i = starts;
int z = ends;
for(i; i < z; i++)
{
[...]
}
}
It's say: Error 3 Only assignment, call, increment, decrement, and new object expressions can be used as a statement.
What to do to make code work?
What to do to make code work?
How about
for (; i < z; i++)
{
[...]
}
OR why creating an extra variable 'z' when you can do
for (int i = starts; i < ends; i++)
{
[...]
}
Why your code doesn't not work!!
Because syntax of for loop is
for (initializer; condition; increment or decrement)
{
}
You were not initializing i in initializer. You could initialize it (as my second snippet) or remove initializer if you are initializing it in some earlier statement(as my first snippet).
i in and of itself is not a statement, it's an expression. In the same way that you can-not simply write i; somewhere in your code. The initialization-part of a for-loop needs to be initialization; however, if (as is the case here) the loop is already initialized (i is already set), you can just omit it as Nikhil showed. Simply do for(;i<z;i++).
The first part of the for loop takes initialization statements. i is not a statement. If you don't want to initialize anything, you can leave that part empty, as in Nikhil's answer:
for(; i < z; i++)
{
[...]
}
Never use outside-defined variables as indexers in for loops.
private void Function(int starts , int ends)
{
// int i = starts; // don't do it. you're exposing yourself to headaches if/when you lose control of the value of i
int z = ends;
for(int i = starts; i < z; i++) //first statement of for loops initializes the indexer
{
[...]
}
}
I think this is the better answer is it not?
private void Function(int starts , int ends)
{
for(int i = starts; i < ends; i++)
{
[...]
}
}

variable scope in statement blocks

for (int i = 0; i < 10; i++)
{
Foo();
}
int i = 10; // error, 'i' already exists
----------------------------------------
for (int i = 0; i < 10; i++)
{
Foo();
}
i = 10; // error, 'i' doesn't exist
By my understanding of scope, the first example should be fine. The fact neither of them are allowed seems even more odd. Surely 'i' is either in scope or not.
Is there something non-obvious about scope I don't understand which means the compiler genuinely can't resolve this? Or is just a case of nanny-state compilerism?
By my understanding of scope, the first example should be fine.
Your understanding of scope is fine. This is not a scoping error. It is an inconsistent use of simple name error.
int i = 10; // error, 'i' already exists
That is not the error that is reported. The error that is reported is "a local variable named i cannot be declared in this scope because it would give a different meaning to i which is already used in a child scope to denote something else"
The error message is telling you what the error is; read the error message again. It nowhere says that there is a conflict between the declarations; it says that the error is because that changes the meaning of the simple name. The error is not the redeclaration; it is perfectly legal to have two things in two different scopes that have the same name, even if those scopes nest. What is not legal is to have one simple name mean two different things in nested local variable declarations spaces.
You would get the error "a local variable named i is already defined in this scope" if instead you did something like
int i = 10;
int i = 10;
Surely 'i' is either in scope or not.
Sure -- but so what? Whether a given i is in scope or not is irrelevant. For example:
class C
{
int i;
void M()
{
string i;
Perfectly legal. The outer i is in scope throughout M. There is no problem at all with declaring a local i that shadows the outer scope. What would be a problem is if you said
class C
{
int i;
void M()
{
int x = i;
foreach(char i in ...
Because now you've used i to mean two different things in two nested local variable declaration spaces -- a loop variable and a field. That's confusing and error-prone, so we make it illegal.
Is there something non-obvious about scope I don't understand which means the compiler genuinely can't resolve this?
I don't understand the question. Obviously the compiler is able to completely analyze the program; if the compiler could not resolve the meaning of each usage of i then how could it report the error message? The compiler is completely able to determine that you've used 'i' to mean two different things in the same local variable declaration space, and reports the error accordingly.
It is because the declaration space defines i at the method level. The variable i is out of scope at the end of the loop, but you still can't redeclare i, because i was already defined in that method.
Scope vs Declaration Space:
http://csharpfeeds.com/post/11730/Whats_The_Difference_Part_Two_Scope_vs_Declaration_Space_vs_Lifetime.aspx
You'll want to take a look at Eric Lippert's answer (who by default is always right concerning questions like these).
http://blogs.msdn.com/ericlippert/archive/2009/08/03/what-s-the-difference-part-two-scope-vs-declaration-space-vs-lifetime.aspx
Here is a comment from eric on the above mentioned post that I think talks about why they did what they did:
Look at it this way. It should always
be legal to move the declaration of a
variable UP in the source code so long
as you keep it in the same block,
right? If we did it the way you
suggest, then that would sometimes be
legal and sometimes be illegal! But
the thing we really want to avoid is
what happens in C++ -- in C++,
sometimes moving a variable
declaration up actually changes the
bindings of other simple names!
From the C# spec on local variable declarations:
The scope of a local variable declared
in a local-variable-declaration is the
block in which the declaration occurs.
Now, of course, you can't use i before it is declared, but the i declaration's scope is the entire block that contains it:
{
// scope starts here
for (int i = 0; i < 10; i++)
{
Foo();
}
int i = 10;
}
The for i variable is in a child scope, hence the collision of variable names.
If we rearrange the position of the declaration, the collision becomes clearer:
{
int i = 10;
// collision with i
for (int i = 0; i < 10; i++)
{
Foo();
}
}
Yea, I second the "nanny-state compilerism" comment. What's interesting is that this is ok.
for (int i = 0; i < 10; i++)
{
}
for (int i = 0; i < 10; i++)
{
}
and this is ok
for (int i = 0; i < 10; i++)
{
}
for (int j = 0; j < 10; j++)
{
var i = 12;
}
but this is not
for (int i = 0; i < 10; i++)
{
var x = 2;
}
var x = 5;
even though you can do this
for (int i = 0; i < 10; i++)
{
var k = 12;
}
for (int i = 0; i < 10; i++)
{
var k = 13;
}
It's all a little inconsistent.
EDIT
Based on the comment exchange with Eric below, I thought it might be helpful to show how I try to handle loops. I try to compose loops into their own method whenever possible. I do this because it promotes readability.
BEFORE
/*
* doing two different things with the same name is unclear
*/
for (var index = 0; index < people.Count; index++)
{
people[index].Email = null;
}
var index = GetIndexForSomethingElse();
AFTER
/*
* Now there is only one meaning for index in this scope
*/
ClearEmailAddressesFor(people); // the method name works like a comment now
var index = GetIndexForSomethingElse();
/*
* Now index has a single meaning in the scope of this method.
*/
private void ClearEmailAddressesFor(IList<Person> people)
{
for (var index = 0; index < people.Count; index++)
{
people[index].Email = null;
}
}
In the first example, the declaration of i outside of the loop makes i a local variable of the function. As a result, it is an error to have another variable name i declared within any block of that function.
The second, i is in scope only during the loop. Outside of the loop, i can no longer be accessed.
So you have seen the errors, but there is nothing wrong with doing this
for (int i = 0; i < 10; i++)
{
// do something
}
foreach (Foo foo in foos)
{
int i = 42;
// do something
}
Because the scope of i is limited within each block.
Or is just a case of nanny-state
compilerism?
Exactly that. There is no sense in "reusing" variable names in the same method. It's just a source of errors and nothing more.
Me thinks that the compiler means to say that i has been declared at the method level & scoped to within the for loop.
So, in case 1 - you get an error that the variable already exists, which it does
& in case 2 - since the variable is scoped only within the for loop, it cannot be accessed outside that loop
To avoid this, you could:
var i = 0;
for(i = 0, i < 10, i++){
}
i = 10;
but I can't think of a case where you would want to do this.
HTH
you need to do
int i ;
for ( i = 0; i < 10; i++)
{
}
i = 10;
class Test
{
int i;
static int si=9;
public Test()
{
i = 199;
}
static void main()
{
for (int i = 0; i < 10; i++)
{
var x = 2;
}
{ var x = 3; }
{ // remove outer "{ }" will generate compile error
int si = 3; int i = 0;
Console.WriteLine(si);
Console.WriteLine(Test.si);
Console.WriteLine(i);
Console.WriteLine((new Test()).i);
}
}
}

Categories