Enclosing Variables Within for Loop

Enclosing variables within for loop

This isn't a complete answer, partly because I'm not sure exactly what the question is (even though I found it quite interesting!).

Instead, I'll just present two alternative for-loops that do work. They've helped clarify the issues in my mind (in particular by helping me to understand for the first time why force() does anything at all in a call to lapply()). I hope they'll help you as well.

First, here is one that's a much closer equivalent of your properly function lapply() call, and which works for the same reason that it does:

a <- c(3,7,11)
f <- list()

## `for` loop equivalent of:
## f <- lapply(1:3, function(i) {force(i); function(x) a[i]+x})
for(i in 1:3) {
f[[i]] <- {X <- function(i) {force(i); function(x) a[i]+x}; X(i)}
}
f[[1]](1)
# [1] 4

Second, here is one that does use local() but doesn't (strictly- or literally-speaking) rename i. It does, though, "rescope" it, by adding a copy of it to the local environment. In one sense, it's only trivially different from your functioning for-loop, but by focusing attention on i's scope, rather than its name, I think it helps shed light on the real issues underlying your question.

a <- c(3,7,11)
f <- list()

for(i in 1:3) {
f[[i]] <- local({i<-i; function(x) a[i]+x})
}
f[[1]](1)
# [1] 4

Can a 'for' loop inside of a 'for' loop use the same counter variable name?

You may use the same name (identifier). It will be a different object. They will not affect each other. Inside the inner loop, there is no way to refer to the object used in the outer loop (unless you make special provisions for that, as by providing a pointer to it).

This is generally bad style, is prone to confusion, and should be avoided.

The objects are different only if the inner one is defined separately, as with the int i you have shown. If the same name is used without defining a new object, the loops will use the same object and will interfere with each other.

JavaScript closure inside loops – simple practical example

Well, the problem is that the variable i, within each of your anonymous functions, is bound to the same variable outside of the function.

ES6 solution: let

ECMAScript 6 (ES6) introduces new let and const keywords that are scoped differently than var-based variables. For example, in a loop with a let-based index, each iteration through the loop will have a new variable i with loop scope, so your code would work as you expect. There are many resources, but I'd recommend 2ality's block-scoping post as a great source of information.

for (let i = 0; i < 3; i++) {
funcs[i] = function() {
console.log("My value: " + i);
};
}

Beware, though, that IE9-IE11 and Edge prior to Edge 14 support let but get the above wrong (they don't create a new i each time, so all the functions above would log 3 like they would if we used var). Edge 14 finally gets it right.



ES5.1 solution: forEach

With the relatively widespread availability of the Array.prototype.forEach function (in 2015), it's worth noting that in those situations involving iteration primarily over an array of values, .forEach() provides a clean, natural way to get a distinct closure for every iteration. That is, assuming you've got some sort of array containing values (DOM references, objects, whatever), and the problem arises of setting up callbacks specific to each element, you can do this:

var someArray = [ /* whatever */ ];
// ...
someArray.forEach(function(arrayElement) {
// ... code code code for this one element
someAsynchronousFunction(arrayElement, function() {
arrayElement.doSomething();
});
});

The idea is that each invocation of the callback function used with the .forEach loop will be its own closure. The parameter passed in to that handler is the array element specific to that particular step of the iteration. If it's used in an asynchronous callback, it won't collide with any of the other callbacks established at other steps of the iteration.

If you happen to be working in jQuery, the $.each() function gives you a similar capability.



Classic solution: Closures

What you want to do is bind the variable within each function to a separate, unchanging value outside of the function:

var funcs = [];

function createfunc(i) {
return function() {
console.log("My value: " + i);
};
}

for (var i = 0; i < 3; i++) {
funcs[i] = createfunc(i);
}

for (var j = 0; j < 3; j++) {
// and now let's run each one to see
funcs[j]();
}

Scope of variables in for loop

The scope of a variable declared in the first part of the for loop is all three parts of the for plus the loop body. In your case the body of the loop is a compound statement, and you declare another variable named i in that block, so it masks the i declared in the for.

So in your piece of code there are three relevant scopes:

  1. The body of the main function
  2. The three parts of the for loop.
  3. The body of the for loop.

And each of them is "internal" to the other, so a variable declared at one of these scopes masks a variable of the same name in a higher scope.

To further illustrate this, if we modify your code as follows:

int main()
{
int i = 9;
printf("outer i: %d\n", i);
for(int i = 5;i>0;printf("middle i:%d\n", i),i--){
int i = 7;
printf("inner i: %d\n",i);
}
printf("outer i: %d\n", i);
}

The output is:

outer i: 9
inner i: 7
middle i:5
inner i: 7
middle i:4
inner i: 7
middle i:3
inner i: 7
middle i:2
inner i: 7
middle i:1
outer i: 9

As for why your code is printing 0 inside of the loop, an uninitialized variable may have any value, including 0. So just because it's printing 0 doesn't mean it's not garbage.

Are variables inside a loop (while or for) disposed after the loop has completed?

Scope and lifetime are two different things. For variables defined at block scope without static, they're more or less tightly linked, but they're still distinct concepts -- and you can shoot yourself in the foot if you don't keep them straight.

Quoting the snippet from the question:

int cc =0;
while(cc < 100){
int X = 99; // <-- this variable
cc++;
}

The scope of X is the region of program text in which its name is visible. It extends from the point at which it's defined to the end of the enclosing block, which is delimited by the { and } characters. (The fact that the block happens to be part of a while statement is not directly relevant; it's the block itself that defines the scope.)

Inside the block, the name X refers to that int variable. Outside the block, the name X is not visible.

The lifetime of X is the time during program execution when X logically exists. It begins when execution reaches the opening { (before the definition), and ends when execution reaches the closing }. If the block is executed 100 times, then X is created and "destroyed" 100 times, and has 100 disjoint lifetimes.

Although the name X is visible only within its scope, the object called X may be accessed (directly or indirectly) any time within its lifetime. For example, if we pass &X to a function, then that function may read and update the object, even though the function is completely outside its scope.

You can take the address of X, and save that address for use after its lifetime has ended -- but doing so causes undefined behavior. A pointer to an object whose lifetime has ended is indeterminate, and any attempt to dereference it -- or even to refer to the pointer's value -- has undefined behavior.

Nothing in particular actually has to happen when an object reaches the end of its lifetime. The language just requires the object to exist during its lifetime; outside that, all bets are off. The stack space allocated to hold the object might be deallocated (which typically just means moving the stack pointer), or, as an optimization, the stack space might remain allocated and re-used for the next iteration of the loop.

Also, is it a bad coding habit to create temporary variables inside a loop?

Not at all. As long as you don't save the object's address past the end of its lifetime, there's nothing wrong with it. The allocation and deallocation will very often be done on entry to and exit from the function rather than the block, as a performance optimization. Restricting variables to a reasonably tight scope is a very good coding habit. It makes the code easier to understand by restricting unnecessary interactions between different parts of the code. If X is defined inside the body of the loop, nothing outside the loop can affect it (if you haven't done something too tricky), which makes it easier to reason about the code.

UPDATE: If X were of a type with a non-trivial constructor and/or destructor, creating and destruction of X actually has to be performed on entry to and exit from the block (unless the compiler is able to optimize that code away). For an object of type int, that isn't an issue.

Python enclosing scope variables with lambda function

Even though i takes multiple values over time, there is effectively only one variable, i. The content of i is being changed during the loop. But the closures captures variables, not values. Nothing is evaluated inside the lambda until you call it. At the time you call the function, you access the current value of i, which happens to be the last one.

As for why i=i solves the problem, this is explained for example in The Hitchhiker's guide to Python (Common Gotchas):

Python’s default arguments are evaluated once when the function is defined, not each time the function is called (like it is in say, Ruby). This means that if you use a mutable default argument and mutate it, you will and have mutated that object for all future calls to the function as well.

And so, each fresh binding that occurs inside the closure you create (and happen to be named i just like the one outside) has its default value being computed when creating the closure. Consequently, you have the "right" value in place, ready to be used when the closure is called.

Does declaring a variable inside a loop body have any disadvantages?

Conceptually that variable is constructed and destructed on each iteration.

But does it affect performance? Well, you can check your case right here. Delete int on line 7 to switch between the loop-local and function-local variables.

Conclusion: no difference whatsoever. The assembly is the same!

So, just use what makes sense in your code. If you need one object per iteration, make one object per. The optimizer is smarter than you think. If that wasn't enough, you'd come back to it with profiling data and careful tweaking, not broad guidelines.

Variable declared in for-loop is local variable?

The reason you are not allowed to define a variable with the same name in both the for-loop as well as outside the for-loop is because variables in the outer-scope are valid in the inner-scope. Meaning that there would be two 'i' variables within the for-loop if this was allowed.

See: MSDN Scopes

Specifically:

The scope of a local variable declared in a local-variable-declaration
(Section 8.5.1) is the block in which the declaration occurs.

and

The scope of a local variable declared in a for-initializer of a for
statement (Section 8.8.3) is the for-initializer, the for-condition,
the for-iterator, and the contained statement of the for statement.

And also: Local variable declarations (Section 8.5.1 of the C# specification)

Specifically:

The scope of a local variable declared in a local-variable-declaration
is the block in which the declaration occurs.
It is an error to refer
to a local variable in a textual position that precedes the
local-variable-declarator of the local variable. Within the scope of a
local variable, it is a compile-time error to declare another local
variable or constant with the same name.

(Emphasis mine.)

Which means that the scope of the i inside your for-loop, is the for-loop. Whereas the scope of the i outside of your for-loop is the entire main method plus the for-loop. Meaning you'd have two occurrences of i inside the loop which is invalid according to the above.

The reason why you're not allowed to do int A = i; is because int i is only scoped for use within the for loop. Thus it is no longer accessible outside of the for loop.

As you can see both of these issues are a result of scoping; the first issue (int i = 4;) would result in two i variables within the for loop scope. Whereas int A = i; would result in access to a variable that is out of scope.

What you could do instead is declare i to be scoped to the entire method, and then use it in both the method as well as the for-loop scope. This will avoid breaking either rule.

public static void Main()
{
int i;

for (i = 0; i < 5; i++)
{

}

// 'i' is only declared in the method scope now,
// no longer in the child scope -> valid.
i = 4;

// 'i' is declared in the method's scope -> valid.
int A = i;
}

EDIT:

The C# compiler could of course be changed to allow this code to compile quite validly. After all this is valid:

for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
}

for (int i = 5; i > 0; i--)
{
Console.WriteLine(i);
}

But would it really be beneficial to your code readability and maintainability to be able to write code such as:

public static void Main()
{
int i = 4;

for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
}

for (int i = 5; i > 0; i--)
{
Console.WriteLine(i);
}

Console.WriteLine(i);
}

Think about the potential for mistakes here, does the last i print out 0 or 4? Now this is a very small example, one which is quite easy to follow and track but it is definitely a lot less maintainable and readable than having declared the outer i by a different name.

N.B:

Please note, C#'s scoping rules differ from C++'s scoping rules. In C++ variables are only in scope from where they are declared until the end of the block. Which would make your code a valid construct in C++.

What is the scope of a 'while' and 'for' loop?

In the following examples all the variables are destroyed and recreated for each iteration of the loop except i, which persists between loop iterations and is available to the conditional and final expressions in the for loop. None of the variables are available outside the loops. Destruction of the variables inside the for loop body occurs before i is incremented.

while(int a = foo()) {
int b = a+1;
}

for(int i=0;
i<10; // conditional expression has access to i
++i) // final expression has access to i
{
int j = 2*i;
}

As for why; loops actually take a single statement for their body, it just happens that there's a statement called a compound statement created by curly braces. The scope of variables created in any compound statement is limited to the compound statement itself. So this really isn't a special rule for loops.

Loops and selection statements do have their own rules for the variables created as a part of the loop or selection statement itself. These are just designed according to whatever the designer felt was most useful.



Related Topics



Leave a reply



Submit