Bear trap in scoping rules

J

John Ramsden

I have a program that calls functions in a module which
I also wrote, and have just wasted two hours chasing a bug
which turned out to be caused by a rogue 'foreach' loop
variable.

I was using a variable exported by the module as the loop
variable of a 'foreach' in the main program, and when a
function in the module was called by the main program,
from within the scope of the foreach, the variable of
the same name in the module had a different value! DUH!?

As soon as I changed the foreach to use a 'my' variable,
everything worked as I had expected.

Just thought I'd mention this strange feature, which seems
to me like a slight flaw (or bug?) in Perl - If variables
in another namespace cannot be used reliably as foreach
loop variables then 'use strict' should warn about this.


Cheers

John Ramsden
 
J

Jeff 'japhy' Pinyan

[posted & mailed]

I have a program that calls functions in a module which
I also wrote, and have just wasted two hours chasing a bug
which turned out to be caused by a rogue 'foreach' loop
variable.

I was using a variable exported by the module as the loop
variable of a 'foreach' in the main program, and when a
function in the module was called by the main program,
from within the scope of the foreach, the variable of
the same name in the module had a different value! DUH!?

As soon as I changed the foreach to use a 'my' variable,
everything worked as I had expected.

Could you post some code as an example? What version of Perl are you
using?
 
M

Matija Papec

X-Ftn-To: John Ramsden

I was using a variable exported by the module as the loop
variable of a 'foreach' in the main program, and when a
function in the module was called by the main program,
from within the scope of the foreach, the variable of
the same name in the module had a different value! DUH!?

As soon as I changed the foreach to use a 'my' variable,
everything worked as I had expected.

Just thought I'd mention this strange feature, which seems
to me like a slight flaw (or bug?) in Perl - If variables
in another namespace cannot be used reliably as foreach
loop variables then 'use strict' should warn about this.

Did you "use strict"?
Can you post relevant code which can reproduce this flaw?
 
A

Anno Siegel

John Ramsden said:
I have a program that calls functions in a module which
I also wrote, and have just wasted two hours chasing a bug
which turned out to be caused by a rogue 'foreach' loop
variable.

I was using a variable exported by the module as the loop
variable of a 'foreach' in the main program, and when a
function in the module was called by the main program,
from within the scope of the foreach, the variable of
the same name in the module had a different value! DUH!?

Of course. Exported variables are package variables which are global
by nature. If you change a global somewhere, you change it everywhere.

If I read this right, you were using a variable exported by the module
as the loop variable of foreach in the main program. This is an utterly
strange arrangement. If you do something like this deliberately (it
*could* make sense), you must be aware of the consequences.

If it happened by accident, that means you used a package variable for
the loop variable, which is considered bad programming practice. You
have just seen why.

The effect you have seen has nothing to do with exportation per se, it
would have shown as well if the variable had been used by a function in
the same file.
As soon as I changed the foreach to use a 'my' variable,
everything worked as I had expected.

Just thought I'd mention this strange feature, which seems
to me like a slight flaw (or bug?) in Perl - If variables
in another namespace cannot be used reliably as foreach
loop variables then 'use strict' should warn about this.

Well, "use strict 'vars'" would have warned against the use of an
unqualified package variable. Only the fact that it was exported, and
hence declared, "saved" you from this warning. It is assumed that you
are aware when you use an imported variable and know what you are doing.

Two lessons can be learned from this:

- Per default, declare all variables (including loop variables) with "my"
in the smallest possible scope.

- Exported variables or functions should have distinctive names, so they
don't easily create name conflicts in the target package.

Anno
 
J

Jeff 'japhy' Pinyan

[posted & mailed]

I have a program that calls functions in a module which
I also wrote, and have just wasted two hours chasing a bug
which turned out to be caused by a rogue 'foreach' loop
variable.

I was using a variable exported by the module as the loop
variable of a 'foreach' in the main program, and when a
function in the module was called by the main program,
from within the scope of the foreach, the variable of
the same name in the module had a different value! DUH!?

I've written a program which exhibits the problem:

$i = 10;
*j = \$i;

for $j (1, 2) {
print "j = $j, i = $i\n";
}

This prints

j = 1, i = 10
j = 2, i = 10

Only the scalar $j is aliased to $i. Compare that with

$i = 10;
*j = *i; # or \*i

for $j (1, 2) {
print "j = $j, i = $i\n";
}

which prints

j = 1, i = 1
j = 2, i = 2

Now, when using a global as the foreach iterator, Perl implicitly
localizes it. What's interesting, though, is that it seems to only
localize the SCALAR portion. I think (*think*) that what that means is
this: if the ENTIRE glob of 'j' is aliased to 'i', then just because $j
is localized, *j is still aliased to *i, so $i and $j hold the same value;
if ONLY $j is aliased to $i, then when $j gets localized, that bond
breaks.

Some other internals-junkie should probably back me up on this one...
 
M

Michael Carman

[posted & mailed]

Now, when using a global as the foreach iterator, Perl implicitly
localizes it. What's interesting, though, is that it seems to only
localize the SCALAR portion. I think (*think*) that what that means is
this: if the ENTIRE glob of 'j' is aliased to 'i', then just because $j
is localized, *j is still aliased to *i, so $i and $j hold the same value;
if ONLY $j is aliased to $i, then when $j gets localized, that bond
breaks.

Some other internals-junkie should probably back me up on this one...

You've got it right. The docs (as of 5.8.0) explain this in the "Symbol
Tables" section of perlmod.

-mjc
 

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
473,755
Messages
2,569,537
Members
45,023
Latest member
websitedesig25

Latest Threads

Top