Simple scope question

  • Thread starter Arthur J. O'Dwyer
  • Start date
A

Arthur J. O'Dwyer

I was paging through Coplien's book "Advanced C++ Programming Styles
and Idioms" this afternoon and found some code that looked something
like

void sort(vector<foo> a)
{
int flip;
do {
for (int i=0, flip = 0; i < a.size(); ++i)
{
for (int j=0; j < i; ++j)
if (a[j] < a) {
swap(a,a[j]);
++flip;
}
}
} while (flip > 0);
return;
}


Now the question: This code doesn't work on my compiler, because
the 'flip = 0' shadows the declaration of 'flip' outside the 'do'
loop. The 'for' loop increments one 'flip', while the 'do' loop
evaluates another.

Is this how it's supposed to work? (I think yes.)
Did it work a different way when Coplien wrote the book? (I think no.)
And are there online errata for Coplien's book? (I couldn't find any.)

Thanks,
-Arthur
 
S

Suzanne Vogel

This code doesn't work on my computer, either, but it's not because of
shadowing. It doesn't work because 'vector<foo> a' is passed as a copy
instead of as a reference. You can see this by tracing with the
debugger. Change it to 'vector<foo>& a' and it should work; it does on
my computer.

But...

** How can anyone explain the following scoping weirdness?

I found that the do-loop looks at the outermost of these two 'flip's
that is *initialized*. When I changed the outermost from 'int flip;' to
'int flip = 1;' I got an infinite loop because then (apparently) the
do-loop always looked at the outermost 'flip'.

Suzanne
 
H

Howard

Suzanne Vogel said:
** How can anyone explain the following scoping weirdness?

I found that the do-loop looks at the outermost of these two 'flip's
that is *initialized*. When I changed the outermost from 'int flip;' to
'int flip = 1;' I got an infinite loop because then (apparently) the
do-loop always looked at the outermost 'flip'.

Suzanne
void sort(vector<foo> a)
{
int flip;
do {
for (int i=0, flip = 0; i < a.size(); ++i)
{
for (int j=0; j < i; ++j)
if (a[j] < a) {
swap(a,a[j]);
++flip;
}
}
} while (flip > 0);
return;
}

Suzanne, it has nothing to do with the first flip variable being initialized
or not (although it DOES have to do with the value it is is being
initialized TO...more on that later). The do itself loop can only 'see' the
first flip instance, because the flip declared inside the the do loop is not
visible at the (outer) scope of the do loop. Everything inside the {} of
the do loop is in an inner scope (if that's the right term), and anything
declared there is out-of-scope outside the {}, including in the while
portion of that loop.

The reason for the infinite loop is that, when you declare it as 1, it will
always be 1 (which is > 0), because the ++flip is operating on the second,
inner flip declaration. If you set it to -1 initially, then the do loop
will excute exactly once, because "-1 > 0" is false.

Howard
 
A

Arthur J. O'Dwyer

[Re Suzanne's comment: This wasn't how Coplien actually wrote the
function, of course. It *was* a bubblesort implementation, but
Coplien's focus was on data structures, while my focus was on that
weird nested-scope thing. So I had just been going to put "..."
everywhere, except that "..." is a token, and then once I started
putting pseudo-C++ everywhere it was needed, it ended up being
a whole function. So the type of 'a' is completely irrelevant, and
it's my fault for trying to make the function look complete. :) ]
{
int flip;
do {
for (int i=0, flip = 0; i < a.size(); ++i)
{
for (int j=0; j < i; ++j)
if (a[j] < a) {
swap(a,a[j]);
++flip;
}
}
} while (flip > 0);
return;
}

Now the question: This code doesn't work on my compiler, because
the 'flip = 0' shadows the declaration of 'flip' outside the 'do'
loop. The 'for' loop increments one 'flip', while the 'do' loop
evaluates another.

Is this how it's supposed to work? (I think yes.)


Yes, this is how it is supposed to work.
Did it work a different way when Coplien wrote the book? (I think no.)

Yes, for loop variables used to have scope that extended to the whole scope
in which the for loop resided. In this case, the sort function itself.
That made the "flip = 0" simply an assignment (as you intended) and not a
declaration.


So what happened to the first definition of 'flip' under these old rules?
Was it treated as a tentative definition? If it had been initialized
originally, and then "re-initialized" in the for loop, would that be an
error? (Just curious.)
The fix is to initialize flip outside (before) the for loop. Looking at
your code, I image you want to initialize it to 0 where you declared it,
outside the do loop, and simply leave it out of the for loop's statement
altogether.

Actually, the correct place for the initialization is right where Coplien
put it - as the first statement executed after (or before, or concurrently
with) the initialization of 'i' to 0. If you initialize 'flip' outside
the 'do' loop, the bubblesort never terminates.

-Arthur
 
K

Karl Heinz Buchegger

Howard said:
[snip]

The fix is to initialize flip outside (before) the for loop. Looking at
your code, I image you want to initialize it to 0 where you declared it,
outside the do loop, and simply leave it out of the for loop's statement
altogether.

That would break the bubble sort !

But he could move the definition of flip inside the do loop
and initialize it there, thus dropping the second definition
from the for loop:

void sort(vector<foo> a)
{
do {

int flip = 0;

for (int i=0; i < a.size(); ++i)
{
for (int j=0; j < i; ++j)
if (a[j] < a) {
swap(a,a[j]);
++flip;
}
}
} while (flip > 0);
return;
}
 
H

Howard

Arthur J. O'Dwyer said:
So what happened to the first definition of 'flip' under these old rules?
Was it treated as a tentative definition? If it had been initialized
originally, and then "re-initialized" in the for loop, would that be an
error? (Just curious.)

It was actually the definition. The difference comes at the for loop
clause, where the flip=0 was treated as an assignment instead of a
definition. Similar to this:

int a;
....
a = 0;

There you have a declaration, and a later assignment. In the old standard,
it did not matter that the assignment was part of a for loop initializer
clause. That's been changed so that the for loop initializer clause is
consistent with a multiple-declaration statement, such as

int b, a = 0;

Since that's a declaration of a, not a simple assignment, the for loop was
changed to behave the same way.

-Howard
 
H

Howard

Karl Heinz Buchegger said:
That would break the bubble sort !


Quite right. The code was obviously wrong somehow, but I didn't bother to
try to analyze how to fix it properly. (What I was pointing out as a fix
was really how to fix the for loop problem in general, not to solve the
problem with the algorithm implementation.)

-Howard
 

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

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top