Strange behavior when declaring index in for loop - c#

Something strange:
for (int i = 0; i < arr.Length; i++)
if (arr[i] > k)
count++;
int i = 0;
This throws an error:
A local parameter named 'i' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
It says that 'i' is already declared, but when I remove the int like this:
for (int i = 0; i < arr.Length; i++)
if (arr[i] > k)
count++;
i = 0;
The name 'i' does not exist in the current context

The scope of a local variable is the whole of the block in which it is declared, including the part of the block before it.
So in your first example, the variable declared on the last line is in scope even though it can't be used (because you can't use a variable before its declaration).
You can't declare a local variable when another local variable with the same name is in scope, which is why the first snippet fails.
The second snippet fails because the scope of the variable declared in the for loop is only the for loop itself.
It might make more sense to remove loops from the picture entirely, and just use blocks. Your first example is similar to this:
// Outer block
{
// Inner block
{
// Error due to the i variable declared in the outer block
int i = 0;
}
// Scope of this variable is the whole of the outer block
int i = 0;
}
Your second example is similar to this:
// Outer block
{
// Inner block
{
// This declaration is fine, and the scope is the inner block
int i = 0;
}
// This is invalid, because there's no variable called "i" in scope
i = 0;
}

class Program
{
static void Main(string[] args) // START PARENT SCOPE
{
for( // START CHILD SCOPE
int i = 0; // This will throw exception because i already exists in the parent scope
i < 10;
i++
)
{
//DO THINGS...
} // END CHILD SCOPE
int i = 10;
} // END PARENT SCOPE
}
The i you defined inside the for loop, is in a child scope of the one you are working after the for loop.
Variables in scopes are considered from the end to the start of a single scope, no matter the order.

You declared i=0 inside the for loop. Then you re-declared it outside the loop. This is why you are having the issue.
But the scope of the variable only is for the loop itself, so you cant use it outside the loop. I hope this makes sense.

Related

How can I take a variable from an if statement in C# [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
this might be a rather stupid question, but im new to this codeing thing. I was wondering if you can take a variable from an if statement and use it outside the if statement as I showed in this exemple down here:
bool ex = true;
if (ex == true)
{
int num = 10;
}
Console.WriteLine(num);
I already tried to declare the variable before the if statement but i gave me an error:
You can declare a variable before if statement and then you can bind a new value to that variable inside if statement and use it outside if statement wherever you required inside your function scope.
bool ex = true;
int num = 0;
if (ex == true)
{
num = 10;
}
Console.WriteLine(num);
Note that i have not used int keyword again while binding value to num variable in if statement as we have defined it already outside of the loop otherwise it will give an error like -> A local variable named 'num' cannot be declared in this scope because it would give a different meaning to 'num'.
Above the if statement write, "
int num;
"
and then inside the if statement write, "
num = 10;
"
You don't have to initialize a variable when you declare it.
The conceptual thing this example teaches is that of local variable scopes.
The body of a method (e.g., Main) is surrounded by { and } characters. This indicates that any variables you declare between these braces can only be written or read to from within the same braces. We call this a "scope". And this applies to most cases of { and } characters, nested within the method.
So in your case:
static void Main()
{ // beginning of method scope
bool ex = true;
if (ex == true)
{ // beginning of if statement scope
int num = 10;
} // end of if statement scope
Console.WriteLine(num);
} // end of method scope
There are two scopes: a scope for the Main method, and a scope within that first scope just for the code inside the { and } after the if.
ex is declared (bool ex) in the outer scope, so you can use it anywhere in the method, including within the inner scope.
num is declared (int num) in the inner scope, so you can only use it within the inner scope, not the outer scope.
To fix this, you can declare a variable, then later assign a value to it. So our next shot would be:
static void Main()
{
bool ex = true;
int num; // declare the variable here
if (ex == true)
{
num = 10; // assign the variable here
}
Console.WriteLine(num);
}
This is closer, but we still get an error, this time:
CS0165 Use of unassigned local variable 'num'
That's because of another rule: in order to use a local variable, the compiler has to be able to know that the variable has always been assigned a value before it's used. In this case, what would happen if ex was false? Then we would declare num, but never give it a value, because the program wouldn't enter into the if scope.
The solution is to give num a value, either at the same time we declare it...
static void Main()
{
bool ex = true;
int num = 5; // declare and assign the variable here
if (ex == true)
{
num = 10; // re-assign the variable here
}
Console.WriteLine(num);
}
...or in an else statement.
static void Main()
{
bool ex = true;
int num; // declare the variable here
if (ex == true)
{
num = 10; // assign the variable here if ex is true
}
else
{
num = 5; // assign the variable here if ex is false
}
Console.WriteLine(num);
}
In the first case, num is given a value as soon as we declare it, so even if we don't enter the if block, num will have a value when we reach Console.WriteLine.
In the second case, the compiler knows that when you chain if and else together, the program is going to go into exactly one of the two. Thus, if we ensure both paths set num, then it will also be guaranteed to have a value once we reach Console.WriteLine.

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.

What is the scope of the counter variable in a for loop?

I get the following error in Visual Studio 2008:
Error 1 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
This is my code:
for (int i = 0; i < 3; i++)
{
string str = "";
}
int i = 0; // scope error
string str = ""; // no scope error
I understand that str ceases to exist once the loop terminates, but I also thought that the scope of i was confined to the for loop as well.
So i has the same scope as a variable declared just outside of the for loop?
Edit:
Just to be clear, I am using C#. I am debating removing the "C" tag. However, since the correct answer explains the difference between the two, I figure it makes sense to leave both tags.
I had an error in my code comment above:
for (int i = 0; i < 3; i++)
{
string str = "";
}
int i = 0; // scope error
string str = ""; // also scope error,
// because it's equivalent to declaring
// string str =""; before the for loop (see below)
I think you're all confusing C++ and C#.
In C++, it used to be that the scope of a variable declared in a for expression was external to the block that followed it. This was changed, some time ago, so that the scope of a variable declared in a for expression was internal to the block that followed it. C# follows this later approach. But neither has anything to do with this.
What's going on here is that C# doesn't allow one scope to hide a variable with the same name in an outer scope.
So, in C++, this used to be illegal. Now it's legal.
for (int i; ; )
{
}
for (int i; ; )
{
}
And the same thing is legal in C#. There are three scopes, the outer in which 'i' is not defined, and two child scopes each of which declares its own 'i'.
But what you are doing is this:
int i;
for (int i; ; )
{
}
Here, there are two scopes. An outer which declares an 'i', and an inner which also declares an 'i'. This is legal in C++ - the outer 'i' is hidden - but it's illegal in C#, regardless of whether the inner scope is a for loop, a while loop, or whatever.
Try this:
int i;
while (true)
{
int i;
}
It's the same problem. C# does not allow variables with the same name in nested scopes.
The incrementor does not exist after the for loop.
for (int i = 0; i < 10; i++) { }
int b = i; // this complains i doesn't exist
int i = 0; // this complains i would change a child scope version because the for's {} is a child scope of current scope
The reason you can't redeclare i after the for loop is because in the IL it would actually declare it before the for loop, because declarations occur at the top of the scope.
Yea. Syntactically: The new scope is inside the block defined by the curly strings. Functionally: There are cases in which you may want to check the final value of the loop variable (for example, if you break).
Just some background information: The sequence doesn't come into it. There's just the idea of scopes - the method scope and then the for loop's scope. As such 'once the loop terminates' isn't accurate.
You're posting therefore reads the same as this:
int i = 0; // scope error
string str = ""; // no scope error
for (int i = 0; i < 3; i++)
{
string str = "";
}
I find that thinking about it like this makes the answers 'fit' in my mental model better..

How this looping works in c#

Recently, in a book i read this code. Can you define the means of this code and how this code works.
int i = 0;
for (; i != 10; )
{
Console.WriteLine(i);
i++;
}
It loops.
Since you already set i=0 above, they have omitted that section of the for loop. Also, since you are incrementing the variable at the end, they have omitted that as well.
They basically just turned a for loop into a while loop.
It would probably be more elegant as:
int i = 0;
while( i != 10 )
{
Console.WriteLine(i);
i++;
}
The for statement is defined in the C# spec as
for (for-initializer; for-condition; for-iterator) embedded-statement
All three of for-initializer, for-condition, and for-iterator are optional. The code works because those pieces aren't required.
For the curious: if for-condition is omitted, the loop behaves as if there was a for-condition that yielded true. So, it would act as infinite loop, requiring a jump statement to leave (break, goto, throw, or return).
If it's easier to see in normal form, it's almost the equivalent of this:
for (int i = 0; i != 10; i++)
{
Console.WriteLine(i);
}
With the exception that it leaves i available for user after the loop completes, it's not scoped to just the for loop.
You are using "for", like a "while"
It's the same as this loop:
for (int i = 0; i != 10; i++) {
Console.WriteLine(i);
}
Except, the variable i is declared outside the loop, so it's scope is bigger.
In a for loop the first parameter is the initialisation, the second is the condition and the third is the increment (which actually can be just about anything). The book shows how the initalisation and increment are moved to the place in the code where they are actually executed. The loop can also be shown as the equivalent while loop:
int i = 0;
while (i != 10) {
Console.WriteLine(i);
i++;
}
Here the variable i is also declared outside the loop, so the scope is bigger.
This code could be rewritten, (in the context of your code snippet - it is not equivalent as stated.) as:
for (int i = 0; i != 10; i++)
Console.WriteLine(i);
Basically, the initializing expression and the increment expression have been taken out of the for loop expression, which are purely optional.
It is same as:
for (int i = 0; i != 10; i++) {
Console.WriteLine(i);
}
Please don't write code like that.
It's just ugly and defeats the purpose of for-loops.
As int i was declared on top so it was not in the for loop.
this is quite like
for(int i = 0; i!=10; i++)
{
/// do your code
}

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