Loop index variable scope
40 次查看(过去 30 天)
显示 更早的评论
I was writing a code in MATLAB and it was something wrong in my output. I spent a lot of time checking each and every thing from the start because MATLAB was not indicating any error in the script. After spending 30 minutes i found that i was using a loop index variabe that was for another loop. Like in the second loop I was mistakenly using i instead of k so instead of giving any error or any warning indication it just used the last value of i=3
Isn't it supposed to give error or warning that variable i is not defined in loop 2 or globally as it is locally defined in loop 1.
for i = 1:3
disp(i)
end
for k = 1:2
disp(i)
end
2 个评论
Robert Laws
2021-11-4
It has long annoyed me that there is no option to turn on loop-scoped indexes.
I am in the habit adding a 'clear x' after each loop end, but that is easy to mess up when later editing the script.
Is there really no way to achieve this?
采纳的回答
Walter Roberson
2021-9-30
No, it is not supposed to give warnings or errors for that.
MATLAB does not have loop-scoped variables (though you could make arguments for local variables inside parfor blocks being loop-scoped.)
When you run a for loop in MATLAB, afterwards the loop control variable is left set to the last value it was assigned inside the loop. Typically that is the last of the for loop values, but it is permitted to modify the index variable inside the loop
for i = 1 : 3
i = i.^2
end
i
This is legal MATLAB, even if confusing.
It makes more sense that the variable would be left as the last value if you consider constructs such as
for i = 1 : 10
if A(i) < 0; break; end
end
then i will be left at the value it had at the time of the break rather than being undefined after the loop. This is useful.
So after the first loop, i is just another variable in memory, and can be used like any other variable. MATLAB does not keep track of it as having most recently been assigned as a loop control variable.
for i = 1 : 10
if A(i) < 0; break; end
end
if rand() < 0.5; i = 3; end
for k = 1 : 2
disp(i);
end
Would it make sense that inside the "for k" that MATLAB should issue a warning or error in the case that i=3 was not executed (in which case i was inherited from the for loop), but should not do so if the i=3 was executed (in which case i was assigned separately) ?
3 个评论
Steven Lord
2022-3-24
Is there a technical limitation that would prevent us from adding such an option to MATLAB? Off the top of my head, I don't think so.
Have there been many requests for this functionality? Again off the top of my head, I believe yours may be the first such request I've seen in MATLAB Answers.
Are there lots of potential questions or pitfalls in how such an option would work? Yes, I can think of a few. Two big ones:
- This seems like an option that if it were toggleable users would want to be able to toggle it programmatically, not just via an option in the Preferences. That's fine, there are other such "toggle" functions in MATLAB (the first one that comes to mind is hold.) But I could see toggling this option inside a for loop as potentially problematic. Not knowing until run-time if the loop variable should continue to exist after the loop is done likely would prevent the execution engine from optimizing the loop code as effectively as it could if it knew at parse-time. This could lead the code to slow down. How large would the slowdown be? I don't know.
- If this option persisted not just inside the scope of a script or function but was a change to the global state of MATLAB, each program (or piece of a program) that wanted to control the state of that option would need to set the option at the start of its code to protect itself. In fact, now that I think about it the situation would be even worse than that; any time a function call or a script execution returned control to the loop, the function or script could have changed the option and so you'd need to set its value again.
Walter Roberson
2022-3-24
for loops that exit early after locating an element of interest are common, as are for loops that exit when a tolerance is met. Perhaps it is your personal programming practice to code such loops as while loops, but coding as for loops is more robust, as it makes certain that the number of iterations is restricted (in case you make a mistake in the termination conditions, such as by forgetting to take into account round-off error.)
Compare
y = [];
for x = initial : increment : stop
run_a_script;
y = f(x);
if y < 5; break; end
end
to
y = [];
if initial < stop
x = [];
else
x_erreimnker_16648809_hidden = initial;
x = x_erreimnker_16648809_hidden;
while true
run_a_script;
y = f(x);
if y < 5; break; end
x_erreimnker_16648809_hidden = x_erreimnker_16648809_hidden + increment;
if x_erreimnker_16648809_hidden > stop
break;
end
x = x_erreimnker_16648809_hidden;
end
clear x_erreimnker_16648809_hidden
end
It is not reasonable to expect that anyone who wanted to break out of a for loop early would rewrite to the equivalent while loop -- and the people who do try the rewrite are highly likely to get the boundary conditions wrong for the case where the loop is not run at all, and for the case where run_a_script modifies the loop control variable.
But... if you do not expect users to rewrite all early-termination for-loops into while loops to avoid the automatic clearing that you propose, then it follows that there has to be a way to enable or disable the proposed changed in behaviour.
setpref('autoclearfor', true)
for K = 1 : 10
y = f(K);
end
Does the hypothetical autoclearfor affect whatever code is inside function f?
Or do you code
%#pragma autoclearfor
for K = 1 : 10
y = f(K);
end
with the pragma not affecting called functions? Does it affect called scripts?
Would the pragma always affect everything in the entire file? Even if the file has multiple functions? Would the pragma always affect everything in the same function only? What about places before that point in the code? What if the user has
for J = 1 : 10
%#pragma autoclearfor
for K = 1 : 10
y = f(K);
end
t = 0;
for Q = 1 : y
t = t + g(Q,y);
end
end
does the pragma affect only the K loop? Does it affect both the K and Q loop? Does it affect the entire file, including the J loop and everything that proceeds that point?
To resolve this, you might use (for example)
for J = 1 : 10
for K = 1 : 10 %#pragma autoclearfor
y = f(K);
end
t = 0;
for Q = 1 : y
t = t + g(Q,y);
end
end
to specifically mark the for K as being affected by the pragma without affecting the J or Q loops. But if you are going to do that... is there any benefit compared to
for J = 1 : 10
for K = 1 : 10
y = f(K);
end
clear K
t = 0;
for Q = 1 : y
t = t + g(Q,y);
end
end
??
It is, in my opinion, not reasonable to create a global preference or pragma that turns the auto-clear behaviour on for all functions. That changes the meaning of far too much code, and gives potentially different results on large quantities of existing MATLAB code depending on whether the preference is on or not. As Steven Lord points out, that leads to needing to inject a lot of "store the state, change it to a known value, restore it afterwards" code needing to be added.
And you have to take into account what happens if you have an error() being handled. If you error out of a loop that has the setting asserted, then is the loop control variable automatically cleared before the catch gets control? Or is it preserved because it might be important for debugging? If you are in a loop that has the setting enabled and you error out of a loop that has the setting disabled (so, preserve expected) but stay within the loop that has the setting enabled, then in the catch should the "preserve" of the nested loop be respected, or should the "clear" of the nesting loop be respected?
Okay, now
J = -inf;
for J = 1 : 10 %#pragma autoclearfor
t = 3;
end
At the end of the loop, should J be -inf? (as if the loop "pushed" a new J onto the stack and removed it afterwards)? Or should it J be cleared after the loop?
It seems to me that there is a lot of questionable behaviour involved in the proposal. My opinion is that the cost of making such a change would be high, and that the benefits would be low.
I think it would make more sense to approach such a proposal through a larger context of lexically scoped variables, something along the lines of
P = zeros(1, 10);
for J = 1 : 10 {
K = max(1, J-2);
P(K) = 5;
}
with the idea being that inside this hypothetical new {} block, any variables assigned to that did not already exist, were to be released upon exit from the block -- so in this case, K would be cleared but already-existing P would not be. In such a situation, we could,
P = zeros(1,10);
{
for J = 1 : 10
K = max(1, J-2);
P(K) = 5;
end
}
The interpretation of this hypothetical extension would be that if J did not already exist then because it is inside a {} block then it would be cleared when the } was reached, and likewise if K did not already exist then it would be cleared at the }, but that already-existing P would not be cleared at the }
My opinion is that this would resolve a number of the difficulties. Not all, though, as the behaviour for try/catch still needs to be considered.
更多回答(0 个)
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Loops and Conditional Statements 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!