Incorrect scope of list comprehension variables

  • Thread starter Alain Ketterlin
  • Start date
M

MRAB

Steven said:
What programming languages were they used to (if any)?

I don't know of any language that creates a new scope for loop variables,
but perhaps that's just my ignorance...
The programming language Ada comes to mind (the variable exists only
within the body of the loop and is read-only like a constant), so yes,
that's just your ignorance. ;-)
 
A

Alf P. Steinbach

* Steven D'Aprano:
What programming languages were they used to (if any)?

I don't know of any language that creates a new scope for loop variables,
but perhaps that's just my ignorance...

MRAB has mentioned Ada, let me mention C++ ...


<code language="C++">
#include <assert.h>

int main()
{
int const i = 42;

for( int i = 0; i < 10; ++i )
{
// blah blah
}
assert( i == 42 );
}
</code>


Java and C# take a slightly different approach where code analogous to the above
won't compile. But it's still a nested scope. E.g. ...


<code language="Java">

class App
{
static public void main( String[] args )
{
for( int i = 0; i < 10; ++i )
{
// blah blah
}

// Uncomment statement below to get compilation error:
//System.out.println( i );
}
}
</code>


So, yes, considering Ada, C++, Java and C# -- and so on. ;-)


Cheers & hth.,

- Alf
 
D

Dave Angel

Steven said:
What programming languages were they used to (if any)?

I don't know of any language that creates a new scope for loop variables,
but perhaps that's just my ignorance...
It's not clear whether a language like C or C++ has "loop variables."
It just has variables with varying scope depending on where they're
declared. And you can add extra braces with the sole purpose being to
introduce new variable scoping.

But two things that changed as C evolved were where you could introduce
new variables, and the lifetime of variables introduced in the loop
control structure, rather than inside the braces. The first change was
in C++ from the start, but I think the second change was also an
evolution in C++.

1) In original C, all declarations in a given scope had to occur before
any executable code began. For example, the following was illegal:
int a=12, b=42;
myfunc(a, b);
int c = 9; /* illegal */

2) In original C, and I think in C++, the lifetime of i lasted long
after the loop ended.
for (int i=0; i< limit; ++i)
{
z += i;
}
i is still valid after this curly brace

In C99, and at least in later C++, the scope of i ends with the curly,
as though there were another invisible pair of braces:
{
for (int i=0; i< limit; ++i)
{
z += i;
}}
i is no longer valid here

Because C and C++ have explicit declarations, people who need the loop
variable after the loop is done can simply declare the loop variable
before the for statement.

DaveA
 
A

Alain Ketterlin

Steven D'Aprano said:
What programming languages were they used to (if any)?

I don't know of any language that creates a new scope for loop variables,
but perhaps that's just my ignorance...

I think Pascal and Modula-2 do this, Fortran does this, as well as Ada.
I'm sure derivatives of Ada like Oracle's PL/SQL also enforce this. And
of course C/C++/Java if the programmer wants it that way. Actually I
think C was the first to consider "for" as some kind of syntactic sugar
for "while" (thus blurring the notion of a for-loop forever). Python's
for is really a member of the for-each family.

May I add that having strict for-loop iterators is a good thing, at
least in languages like C/C++/Fortran/etc. Optimizing compilers usually
spend some time detecting so-called "induction variables" when they're
not given: it helps simplifying loop bodies, it reduces register
pressure, and changes many array accesses into pointer increments, among
other things.

-- Alain.
 
S

Steven D'Aprano

I think Pascal and Modula-2 do this, Fortran does this, as well as Ada.

Pascal doesn't do this.

[steve@sylar pascal]$ cat for_test.p
program main(input, output);
var
i: integer;
begin
for i := 1 to 3 do
begin
writeln(i);
end;
writeln(i);
end.

[steve@sylar pascal]$ gpc for_test.p
[steve@sylar pascal]$ ./a.out
1
2
3
3


However you can't assign to the loop variable inside the loop. Outside of
the loop, it is treated as just an ordinary variable and you can assign
to it as usual.
 
A

Alain Ketterlin

Steven D'Aprano said:
I think Pascal and Modula-2 do this, Fortran does this, as well as Ada.

Pascal doesn't do this. [...]
for i := 1 to 3 do
begin
writeln(i);
end;
writeln(i);
[...]

At http://standardpascal.org/iso7185.html#6.8.3.9 For-statements
(sorry, I didn't find a more readable version), I read (second
paragraph, fourth sentence) :

"After a for-statement is executed, other than being left by a
goto-statement, the control-variable shall be undefined."

So, at least, the compiler should emit a warning.
However you can't assign to the loop variable inside the loop. Outside of
the loop, it is treated as just an ordinary variable and you can assign
to it as usual.

I read the excerpt above as: you have to re-assign to it before using it.

The corner-case is obvious: if the loop body is not executed at all,
you cannot assume the "control-variable" will have the first value. I'm
curious to know what gets printed if you swap 1 and 3 in the above code.

-- Alain.
 
S

Steven D'Aprano

Steven D'Aprano said:
I don't know of any language that creates a new scope for loop
variables, but perhaps that's just my ignorance...

I think Pascal and Modula-2 do this, Fortran does this, as well as
Ada.

Pascal doesn't do this. [...]
for i := 1 to 3 do
begin
writeln(i);
end;
writeln(i);
[...]

At http://standardpascal.org/iso7185.html#6.8.3.9 For-statements
(sorry, I didn't find a more readable version), I read (second
paragraph, fourth sentence) :

"After a for-statement is executed, other than being left by a
goto-statement, the control-variable shall be undefined."

So, at least, the compiler should emit a warning.

None of my Pascal text books mention this behaviour, and gpc doesn't emit
a warning by default. Possibly there is some option to do so.

Stardard Pascal isn't as useful as non-standard Pascal. This was one of
the reasons for the (in)famous article "Pascal Considered Harmful" back
in the 1980s(?).

I read the excerpt above as: you have to re-assign to it before using
it.

The corner-case is obvious: if the loop body is not executed at all, you
cannot assume the "control-variable" will have the first value. I'm
curious to know what gets printed if you swap 1 and 3 in the above code.

When I try it, i is initialised to 0. That either means that gpc zeroes
integers when they're declared, or the value it just randomly happened to
pick up was 0 by some fluke. I'm guessing the first is more likely.
 
D

Dennis Lee Bieber

At http://standardpascal.org/iso7185.html#6.8.3.9 For-statements
(sorry, I didn't find a more readable version), I read (second
paragraph, fourth sentence) :

"After a for-statement is executed, other than being left by a
goto-statement, the control-variable shall be undefined."

So, at least, the compiler should emit a warning.
I suspect what they meant is that the final value is compiler
dependent -- it could hold either the last index used within the loop...
OR it might have been incremented to the next value past the end
point... Whereas leaving the loop by GOTO is known to have the "current"
index value.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,175
Messages
2,570,942
Members
47,489
Latest member
BrigidaD91

Latest Threads

Top