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++)
{
[...]
}
}
Related
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.
I have this iterator and want it to stop on some condition, thus, there is a 3rd parameter called "condition".
public static IEnumerable<long> Dates(long start, int step, bool condition)
{
var k = start + step;
while (condition)
{
k += step;
yield return k;
}
}
I call it this way :
var i = 0;
foreach (var k in Iterator.Dates(0, 5, i++ < 100))
{
// Here goes infinite loop because (i++ < 100) is always true inside iterator
}
Unfortunately, this parameter does not change inside loop so now it is always true because seems that it gets executed only on the first iteration.
Question : how to check or execute "condition" on each iteration?
Argument is bool, but you need predicate function like this:
public static IEnumerable<long> Dates(long start, int step, Func<bool> condition)
{
var k = start + step;
while (condition())
{
k += step;
yield return k;
}
}
Usage:
var i = 0;
foreach (var k in Dates(0, 5, () => i++ < 100))
{
// Here goes infinite loop because (i++ < 100) is always true inside iterator
}
Comments
() => i++ < 100 is lambda expression similar to boolean function without arguments that returns i++ < 100.
What you want to provide is a piece of functionality, a rule. Instead you have provided a value, and this value is calculated in the expression before the method is called and thus inside the method it is constant, never changes, exactly like you observed.
Instead you need to pass in a delegate, you "delegate" the responsibility of providing the rule to the caller.
A simple delegate type appropriate for this example is Func<T> which is basically defined like this:
public delegate T Func<T>();
This is a delegate that wraps a method that returns a value, without taking any parameters.
Since you want to use the result of this function in a while statement, you need it to return bool.
Here's how you would declare the method:
public static IEnumerable<long> Dates(long start, int step, Func<bool> condition)
{
var k = start + step;
while (condition())
{
k += step;
yield return k;
}
}
Note that you need to change the while expression to call the delegate. Since it wraps a method, to obtain the value from the method you have to call it.
Here's how to call the new method:
var i = 0;
foreach (var k in Iterator.Dates(0, 5, () => i++ < 100))
{
// No longer infinite loop because (i++ < 100) is now evaluated on every iteration
}
This new expression:
() => i++ < 100
is basically the same as writing this:
int i;
bool Func()
{
return i++ < 100;
}
but wrapped in a smaller syntax.
Now, every time the loop runs one iteration, it will call this func, which will increase the value and compare it to 100.
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
}
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);
}
}
}
Is there a way of calling a method/lines of code multiple times not using a for/foreach/while loop?
For example, if I were to use to for loop:
int numberOfIterations = 6;
for(int i = 0; i < numberOfIterations; i++)
{
DoSomething();
SomeProperty = true;
}
The lines of code I'm calling don't use 'i' and in my opinion the whole loop declaration hides what I'm trying to do. This is the same for a foreach.
I was wondering if there's a looping statement I can use that looks something like:
do(6)
{
DoSomething();
SomeProperty = true;
}
It's really clear that I just want to execute that code 6 times and there's no noise involving index instantiating and adding 1 to some arbitrary variable.
As a learning exercise I have written a static class and method:
Do.Multiple(int iterations, Action action)
Which works but scores very highly on the pretentious scale and I'm sure my peers wouldn't approve.
I'm probably just being picky and a for loop is certainly the most recognisable, but as a learning point I was just wondering if there (cleaner) alternatives. Thanks.
(I've had a look at this thread, but it's not quite the same)
Using IEnumerable without foreach loop
Actually, the for loop does not hide what you're trying to do.
Anyone reading your code is already familiar with standard for loops and will understand instantly what you're doing.
You could score even more highly on the pretension scale by making it an extension method:
public static void Times(this int iterations, Action action)
{
for (int i = 0; i < iterations; i++)
{
action();
}
}
...
6.Times(() => {
DoSomething();
SomeProperty = true;
});
But I would definitely stick with a for loop. It's the idiomatic, well-recognised way of doing it.
Not a loop in sight
private MethodDelegate MultiMethod(MethodDelegate m, int count) {
MethodDelegate a;
if (count > 0) {
a = m;
a += MultiMethod(m, --count);
} else {
a = delegate { };
}
return a;
}
and you get a great syntax for invocation!
MultiMethod(action, 99)();
How about a do....until or if...then
Use a counter inside the loop and have it loop UNTIL the counter reaches 6.
Or an if-then statement with a counter. If your value is 6, break out of the loop.
I'm not a programming guru, but if you have an action that needs to be done a set number of times, there would be a need for a counter somewhere, whether it's a function of your loop or if it has to be created with a counter.