Topic: Scope of variables declared in for-loop


Author: jason@cygnus.com (Jason Merrill)
Date: 06 Mar 1995 23:52:02 GMT
Raw View
>>>>> Christian Millour <chris@alofi.etca.fr> writes:

> Remember, the Algol68 notion that a declaration can be introduced
> whenever it is needed (and not just at the top of a block) is
> totally redundant in C++. If you need it, add a block.

Indeed, this is basically how mid-block declarations are handled in GNU
C++.

Jason




Author: mueller@garwein.hai.siemens.co.at (Harald M. Mueller)
Date: Mon, 6 Mar 1995 13:24:42 GMT
Raw View
[I lost the original subject somewhere, something woth ANSI and for ...]


To add another viewpoint to the debate about the loop-declaration scope
(although this debate has already found its way into C++Report; and it
seems that the committee has already settled on the issue ...):

IMHO, there is a good reason why the "new way" for declaring iterators
which are used outside the loop

   int i;
   for(i=0; i<n; i++) {
  ...
 }
   x[i] = 0;

is significantly worse than the current one

   for (int i=0; i<n; i++) {
  ...
 }
   x[i] = 0;

The reason is that in the former, it is necessary to construct a "dangling
iterator" for a short while and, even worse, makes it necessary
to provide a constructor which will construct such a dangling iterator.
In our project, we have lots of loops of the following kind:

 for (Iterator<XXX> i_x = a_set_of_XXX; i_x.valid(); ++i_x) {
     ...
     }
 if (i_x.valid()) {
     ...
     }

We cannot change this to

 Iterator<XXX> i_x;
 for (i_x = a_set_of_XXX; i_x.valid(); ++i_x) {
etc.

as neither a parameterless constructor nor an assignment are defined for
Iterator<XXX> (please no arguments that they should be defined ... some of
these iterators have very complicated internal machinery, as they are very
"safe" iterators; there is simply no [easy] semantics of assignment which
makes sense with these iterators, and we do not see any good reason why we
should define some artificial one [e.g. only the parameterless constructor
creates a "no-good"-iterator, which can then be assigned to? but then we
would have to have a run-time check in the assignment whether
the iterator assigned to is indeed the no-good one, which (a) takes time
(which is wasted if the program is correct) and (b) no-one wants to change
static checks to runtime checks, anyway]).

We could instead write

 Iterator<XXX> i_x = a_set_of_XXX;
 for (; i_x.valid(); ++i_x) {
etc.

and we could even define a macro for that:

 #define our_for(init,test,incr) init; for(;test;incr)

or something like that.

Should we? I, IMHO, find this approach ugly and "not in the spirit of C++"
(which, after all, initially came up with the possibility of declaring a loop
variable in the for statement).

On the other hand [yes, I'm split-brain here ...], I have wanted these
if-declarations for a long time; and the longer I look at them, the more
I find that it is *right* that their scope ends with the branch(es) of the
if. The "correction" of the for-statement is then a must ...

So we will rewrite all our loops to

 Iterator<XXX> i_x = a_set_of_XXX;
 for (; i_x.valid(); ++i_x) {

and make this a PATTERN - albeit an ugly one!

HMMueller


== --------------------------------------------------------------
== Dr. Harald M. Mueller mueller@garwein.hai.siemens.co.at
== Siemens AG Austria  Siemens AG Austria
== EZE 41   Erdberger Laende 26
== fax: +43-1-71711-5425 A-1030 Vienna/Austria
== --------------------------------------------------------------








Author: chris@alofi.etca.fr (Christian Millour)
Date: 6 Mar 1995 15:12:35 GMT
Raw View
In article <1995Mar6.132442.5446@siemens.co.at>, mueller@garwein.hai.siemens.co.at (Harald M. Mueller) writes:
|> So we will rewrite all our loops to
|>
|>  Iterator<XXX> i_x = a_set_of_XXX;
|>  for (; i_x.valid(); ++i_x) {
|>
|> and make this a PATTERN - albeit an ugly one!

As such it *is* ugly, and even nasty at that. But consider the
larger picture, and add an extra set of braces ending after your
last use of the iterator :
   ...
   {
      Iterator<XXX> i_x = a_set_of_XXX;
      for (; i_x.valid(); ++i_x) {
         ...
      }
      if (i_x.valid()) {
         ...
      }
   }
   ....

call *this* a pattern (IMHO one you should have inherited from
your C days) and you're one tiny but significant step higher on
the Infinite Stairway of Modularization and Reusability that we
are all trying to ascend (aren't we ?).

Remember, the Algol68 notion that a declaration can be introduced
whenever it is needed (and not just at the top of a block) is
totally redundant in C++. If you need it, add a block. I can't think
of any undesirable effects of adding blocks, apart from extra indentation
and maybe 2 wasted LOCs on your editor screen (if you know of any other
please post it). On the contrary, I can think of many desirable ones.
If anything, it makes code cut-and-paste or macroization *much* safer.

--chris@etca.fr

|> HMMueller
|>
|>
|> == --------------------------------------------------------------
|> == Dr. Harald M. Mueller mueller@garwein.hai.siemens.co.at
|> == Siemens AG Austria  Siemens AG Austria
|> == EZE 41   Erdberger Laende 26
|> == fax: +43-1-71711-5425 A-1030 Vienna/Austria
|> == --------------------------------------------------------------
|>
|>
|>
|>