[comp.lang.c++] FORever

ron@sco.COM (Ron Irvine) (09/28/90)

BEWARE there is a major problem with C++'s "for" statement.

main() {
	for (int i=10; i<13;) {
		for (int i=0; i<3; ++i)
			; // stuff
		++i;
	}
}

Cfront accepts this code and compiles without warning.
The resulting code is totally unexpected!
The program loops forever?!!

I realize the problem is that cfront does not end the
scope of the inners loop's "i" until the end of the
outer loop, thus the "++i;" statement actually increments
the inner loops "i" whos scope is the outer loop.  And I
did not "redeclare" "i" in the outer loop since the outer
"i"'s scope is outside the outer loop.

This is a bad joke for a language that is designed for the 90's.
The scope of a variable in a "for-init-statement" MUST end
at the end of the "for" statement. Lets change the definition of
the language NOW before we inflict horrendous pain on C++ programmers.

landauer@morocco.Eng.Sun.COM (Doug Landauer) (09/30/90)

ron> BEWARE there is a major problem with C++'s "for" statement.
ron> 
ron> main() {
ron>   	for (int i=10; i<13;) {
ron> 		for (int i=0; i<3; ++i)
ron> 			; // stuff
ron> 		++i;
ron> 	}
ron> }

It looks even worse than this if you put in the braces that
the inner "for" should have had:

	main() {
		for (int i=10; i<13;) {
			for (int i=0; i<3; ++i) {
				; // stuff
			}
			++i;
		}
	}

That is, now the "++i;" is outside of the inner for's braces, and
looks (to the C programmer's eye) even less a part of it than in
your example, but it still refers to the inner for's "i".

ron> Let's change the definition of
ron> the language NOW before we inflict horrendous pain on C++ programmers.

Too late.  To change it now would indeed inflict too much pain on
programmers who have existing C++ code that depends on this decision.

My suggestion is to adhere to a C++-Style-Guide rule that says:
***Whenever*** you declare a variable within a "for" loop, surround the
for loop with an extra set of braces, starting before the "for"
keyword.  Thus, I would have written your example like so:

	main() {
		{for (int i=10; i<13;) {
			{for (int i=0; i<3; ++i) {
				; // stuff
			}}
			++i;
		}}
	}

This also improves the situation in those cases where you
have two non-nested loops, both using the same variable:

	main() {
		{for (int i=10; i<13; ++i) {
			; // Do some stuff to 3 somethings
		}}

		// Do other stuff

		{for (int i=10; i<13; ++i) {
			; // Do some stuff to 3 other somethings
		}}
	}

Now, you no longer get the "two declarations of i" error message when
you copy a for loop to another part of the same function, and you get a
visually distinct way of showing that the "i" in this for loop really
belongs only inside the loop.  When you really do want to use "i" after
the loop is over, *then* you can break the double-brace apart, and of
course you would then give the loop an extra indentation level.

marc> Do you really want to break all the existing code that does something like
marc> 
marc>     for (int i=10; i<13; ++i) {
marc> 	     if (x[i] == magicValue) {
marc> 	         break;
marc> 	     }
marc>     }
marc>     if (i >= 13) {
marc> 	     // we didn't find magicValue
marc>     }

Under the proposed rule, this becomes

	{ // contain the scope of "i"
	    for( int i=10; i < 13; ++i) {
		    if( x[i] == magicValue) {
			    break;
		    }
	    }
	    if( i >= 13 {
		// we didn't find magicValue
	    }
	} // end scope of "i"

marc> Lots of C code uses this.

No C code uses this; it's not C code.  The ANSI C standard won't let you
declare a variable within that () part of a "for" loop, and I've never seen
any C compiler which would allow it, either.   However, lots of C++ code
does use this.  [ You have to, if you write any member functions.  :-) ]

marc> I assume (which will probably get me into
marc> trouble) that C++ programmers will want to do the same thing.

No trouble here -- C++ programmers will want to do almost any damn
thing that cfront will allow them to do.  Worse, C++ programmers
still want to do any damn thing that cfront has ever allowed them
to do.  (... and people in hell want icewater ...)
-- 
Doug Landauer - Sun Microsystems, Inc. - Languages - landauer@eng.sun.com
    Matt Groening on C++:  "Our language is one great salad."

ark@alice.att.com (Andrew Koenig) (10/01/90)

In article <212@dumbcat.sf.ca.us>, marc@dumbcat.sf.ca.us (Marco S Hyman) writes:

> Do you really want to break all the existing code that does something like

>     for (int i=10; i<13; ++i) {
> 	if (x[i] == magicValue) {
> 	    break;
> 	}
>     }
>     if (i >= 13) {
> 	// we didn't find magicValue
>     }

> Lots of C code uses this.

I hope not -- it isn't legal C.

C does not allow variables to be declared in `for' statements;
instead one must write something like this:

    int i;
    for (i=10; i<13; ++i) {
	if (x[i] == magicValue) {
	    break;
	}
    }
    if (i >= 13) {
	// we didn't find magicValue
    }

The meaning of such things would not be affected by any change
in the scope of C++ variables declared in `for' statements.
-- 
				--Andrew Koenig
				  ark@europa.att.com

graham@convex.com (Marv Graham) (10/02/90)

In article <1990Sep27.150948.9109@sco.COM> ron@sco.COM (Ron Irvine) writes:
>
>BEWARE there is a major problem with C++'s "for" statement.
>
>main() {
>	for (int i=10; i<13;) {
>		for (int i=0; i<3; ++i)
>			; // stuff
>		++i;
>	}
>}
>
>Cfront accepts this code and compiles without warning.
>The resulting code is totally unexpected!
>The program loops forever?!!
>
>I realize the problem is that cfront does not end the
>scope of the inners loop's "i" until the end of the
>outer loop, thus the "++i;" statement actually increments
>the inner loops "i" whos scope is the outer loop.  And I
>did not "redeclare" "i" in the outer loop since the outer
>"i"'s scope is outside the outer loop.
>
>This is a bad joke for a language that is designed for the 90's.
>The scope of a variable in a "for-init-statement" MUST end
>at the end of the "for" statement. Lets change the definition of
>the language NOW before we inflict horrendous pain on C++ programmers.

In my opinion, the PROBLEM is using a badly defined new toy instead
of writing

main() { int i ;	// this really belongs here
	for (i=10; i<13;) {
	    {	// this really is needed here
		int	i ;	// and this really belongs here
		for (i=0; i<3; ++i)
			; // stuff
	    }	// this makes the next ++i refer to the outer one
		++i;
	}
}

If you say what you mean, you get what you want.

What we should really do is make the nested definitions illegal (again)!

But, if you had just a little common sense, you would write

main() { int	i ;
	for (i=10; i<13;) {
		int	j ;	// what, not "i" again??
		for (j=0; j<3; ++j)
			; // stuff
		++i;
	}
}

Can't you really think of a name for a for loop index besides "i"?

Marv Graham; Convex Computer Corp.  {uunet,sun,uiucdcs,allegra}!convex!graham

cory@howtek.UUCP (Cory Kempf) (10/03/90)

In article <1990Sep27.150948.9109@sco.COM> ron@sco.COM (Ron Irvine) writes:
>
>BEWARE there is a major problem with C++'s "for" statement.

No, the for statement works as it should...

>main() {
>	for (int i=10; i<13;) {
>		for (int i=0; i<3; ++i)
>			; // stuff
>		++i;
>	}
>}
>
>Cfront accepts this code and compiles without warning.
>The resulting code is totally unexpected!

hardly.  see below.  I will try to refrain from comment about
poor programming style.

>The program loops forever?!!

Of course it loops forever!  That is what you told it 
to do.  Think about how that structure would be implimented
in C:

  main() {
    int i;
    for(i=10;i<13;) {
      int i;	    // hides previous i
      for (i=0; i<3; ++i)
	    ; // stuff
      ++i;		// note the scope of i
    }
  }

The result is, I believe, obvious.

>I realize the problem is that cfront does not end the
>scope of the inners loop's "i" until the end of the
>outer loop, thus the "++i;" statement actually increments
>the inner loops "i" whos scope is the outer loop.  

This is a documented behaviour by the way.  

+C

marc@dumbcat.sf.ca.us (Marco S Hyman) (10/04/90)

In article <11410@alice.att.com> ark@alice.att.com (Andrew Koenig) writes:
    In article <212@dumbcat.sf.ca.us> I wrote:
    
    > Do you really want to break all the existing code that does something
    > like
    
    >  for (int i=10; i<13; ++i) {
    > 	if (x[i] == magicValue) {
    > 	    break;
    > 	}
    >  }
    >  if (i >= 13) {
    > 	// we didn't find magicValue
    >  }

Thanks to Andrew (and the others who send e-mail) for pointing out my
stupid slip -- it is not and never has been C code.

But the question still remains -- does the C++ community favor
dissallowing the above code?  I've seen this style used in C++ programs. (I
didn't like it when I saw it, either).

// marc
-- 
// marc@dumbcat.sf.ca.us
// {ames,decwrl,sun}!pacbell!dumbcat!marc

schmidt@indetech.com (Douglas C. Schmidt) (10/11/90)

[ED note: This is posted on behalf of Jim Roskind]

----------------------------------------
In article <1990Sep27.150948.9109@sco.COM> ron@sco.COM (Ron Irvine) writes:
    
ron> BEWARE there is a major problem with C++'s "for" statement.
ron> 
ron> main() {
ron>   	for (int i=10; i<13;) {
ron> 		for (int i=0; i<3; ++i)
ron> 			; // stuff
ron> 		++i;
ron> 	}
ron> }
ron>     
ron> ...
ron>    
ron> This is a bad joke for a language that is designed for the 90's.
ron> The scope of a variable in a "for-init-statement" MUST end
ron> at the end of the "for" statement. Lets change the definition of
ron> the language NOW before we inflict horrendous pain on C++ programmers.

Response From: marc@dumbcat.sf.ca.us (Marco S Hyman)
Marco> 
Marco> Do you really want to break all the existing code that does something like
Marco> 
Marco>     for (int i=10; i<13; ++i) {
                ^^^^^^^^
Marco> 	if (x[i] == magicValue) {
Marco> 	    break;
Marco> 	}
Marco>     }
Marco>     if (i >= 13) {
Marco> 	// we didn't find magicValue
Marco>     }
Marco> 
Marco> Lots of C code uses this.  I assume (which will probably get me into
              ^^^
Marco> trouble) that C++ programmers will want to do the same thing.
Marco> 

Actually, since C code does *not* allow declarations in the middle of
a "for" statement, this adjustment does *not* seem to break any "old C
code".  When C++ programmers "want to do the same thing", I think they
would be well advised to clearly locate the declaration of the
iteration variable at the scope in which they intend to use the
variable (i.e., declare "i" before the "for" statement if the intent
is to continue using it after the "for" statement).  This approach is
actually what C programmers have always been doing :-).

I am aware that current semantic rules (re: E&S and cfront) support
the odd behavior wherein variables declared in the for statement are
"exported" to the enclosing scope.  From my view, this would appear to
be a "bug" in cfront that has grown to be gospel in E&S.  I can only
hope that enough programmers will take it upon themselves to avoid use
of such arguable semantic decisions, with the belief that the decision
*might* some day be changed.  If enough programmers take this
enlightened view, it may be possible to make the transition, but
otherwise C++ will slowly be saddled with more than the heritage and
compatibility with C, it must also forever support its initial
decisions (accidents?).

I personally don't think that any of the little quirks in C++ (this is
only one) can, in and of themselves individually, damage the language.
I tend to wonder when the summation of the many quirks might actually
end up hindering the language and its use/implementation.  

I agree  with Ron Irvine,  and I would  like to see  the for statement
limit the   scope of declared  variables  to  its  own  "for statement
scope".  I figure every little bit of  improvement helps the language,
but the questions of compatibility  haunt me, as the trade-off between
good language design and "existing" code are beyond me.




-- 
Jim Roskind-   Author of a YACCable C++ grammar
Independent Consultant
(407)729-4348 or (617)577-9813 x5570
jar@hq.ileaf.com or ...!uunet!leafusa!jar


-- 
____*_  Douglas C. Schmidt          schmidt@indetech.com
\  / /  Independence Technologies   {sun,sharkey,pacbell}!indetech!schmidt
 \/ /   42705 Lawrence Place        FAX: 415 438-2034
  \/    Fremont, CA 94538           Voice: 415 438-2023

daves@ex.heurikon.com (Dave Scidmore) (10/17/90)

In article <1990Sep27.150948.9109@sco.COM> ron@sco.COM (Ron Irvine) writes:
    
ron> BEWARE there is a major problem with C++'s "for" statement.
ron> 
ron> main() {
ron>   	for (int i=10; i<13;) {
ron> 		for (int i=0; i<3; ++i)
ron> 			; // stuff
ron> 		++i;
ron> 	}
ron> }
ron> ...
ron> This is a bad joke for a language that is designed for the 90's.
ron> The scope of a variable in a "for-init-statement" MUST end
ron> at the end of the "for" statement. Lets change the definition of
ron> the language NOW before we inflict horrendous pain on C++ programmers.

Response From: marc@dumbcat.sf.ca.us (Marco S Hyman)
Marco> 
Marco> Do you really want to break all the existing code that does something like
Marco> 
Marco>     for (int i=10; i<13; ++i) {
                ^^^^^^^^
Marco> 	if (x[i] == magicValue) {
Marco> 	    break;
Marco> 	}
Marco>     }
Marco>     if (i >= 13) {
Marco> 	// we didn't find magicValue
Marco>     }
Marco> 
Marco> Lots of C code uses this.  I assume (which will probably get me into
Marco> trouble) that C++ programmers will want to do the same thing.
Marco> 

> Actually, since C code does *not* allow declarations in the middle of
> a "for" statement, this adjustment does *not* seem to break any "old C
> code".

My assumption would be that he wished to say break existing C++ code and
accidentaly wrote existing C code.

> I am aware that current semantic rules (re: E&S and cfront) support
> the odd behavior wherein variables declared in the for statement are
> "exported" to the enclosing scope.  From my view, this would appear to
> be a "bug" in cfront that has grown to be gospel in E&S.

Since this "bug", as you call it, also appears in "The C++ Programming
Language" semantic rules, and since the language had been in use at AT&T for
some time before either book was published I can only assume it was a
carefully considered decision and not a bug.
	Faced with the same decision I have to admit that I would have made
the same choice. To make the variable a part of the outer scope allows it to
be used after the end of the "for" statement while restricting it to the
inner scope only prevent problems where bad programming practices are used,
i.e. multiple variables with the same name in different scopes.
On top of this the variable actualy appears outside the curly braces
which delimit the inner scope, making it intuitively obvious that it is not
a part of that scope. If curly braces introduce a new scope, as the
semantic rules for C++ state then the "for" loop variable must be part of the
outer scope and not the inner one.

> I personally don't think that any of the little quirks in C++ (this is
> only one) can, in and of themselves individually, damage the language.

It is poor form to use unnamed "quirks" as an argument. Give us examples.

> I agree  with Ron Irvine,  and I would  like to see  the for statement
> limit the   scope of declared  variables  to  its  own  "for statement
> scope".

I dissagree. I have had no problem dealing with this rule and understanding
its consequences from the first time I read about it. I also would submit that
the current scope rules provided by E&S are consistent and that the rule you
are proposing is not.

--
Dave Scidmore, Heurikon Corp.
dave.scidmore@heurikon.com