DeaconBlues has asked for the wisdom of the Perl Monks concerning the following question:

Here at work, my coworkers and I are maintaining a system which was written in perl 4 and partially converted to perl 5.004. We now run this code under perl 5.6. Surprise! scoping of variables is a major item of confusion when something needs to be fixed. So here is our lastest confusion, we ran into this occurence, and would be helped by some PM clarification.

We have a module with some global "my" variables. Ex: File: foo.pm

package foo; my $foo = 5; my $bar = 7; sub set_foobar { $foo = 6; $foo::bar = 8; }

Then we have a script that calls the subroutine "set_foobar". Ex: File: test.pl

use foo; print $foo::foo,"\n"; print $foo::bar,"\n"; foo::set_foobar(); print $foo::foo,"\n"; print $foo::bar,"\n";

Results:

Use of uninitialized value in print at test.pl line 6. Use of uninitialized value in print at test.pl line 7. Use of uninitialized value in print at test.pl line 13. 8

If "my" creates private variables, then what happens to this private variable when someone sets a value while stating its package name explicity. Why is it now available publicly?

Thanks
Dave

Replies are listed 'Best First'.
Re: "my" variables going public?
by arturo (Vicar) on May 21, 2001 at 23:22 UTC

    my variables don't live in a symbol table, and so don't have fully qualified names.

    Package variables (aka package globals) do, and do respectively.

    so

    package foo; my $foo = 'bar';

    does not set $foo::foo. The call to set $foo in the subroutine sees only the my variable, because the use of my to declare a $foo masks the package global.

    Note also that this 'masking' works even through different packages. my variables are visible within their scope, which can cross package boundaries.

    That makes sense, because one always has a way of accessing $foo::foo with a fully qualified name, but you won't have that with my.

    does that help?

      So for my example module foo.pm, $bar and $foo::bar are completely separate variables. And anywhere you access $foo::bar you will never get any value attached to $foo. Correct?

        $foo::bar *is* set in the subroutine in foo.pm. So it's visible everywhere after that subroutine is executed, as $foo::bar.

        The $foo=6; in that sub sets the my variable to 6. You get an uninitialized value error at line 7 because you haven't called foo:set_foobar yet, but the next time you try to print out that value (at line 13), you have.

        You code, as it stands, *never* sets $foo::foo. And, unless it is the return value of a sub in foo.pm, you'll never be able to see the value of that my variable in any code that lives outside foo.pm

        For more goodness on this stuff, check out Dominus' home node and follow the link to "Coping With Scoping".

        HTH

(tye)Re: "my" variables going public?
by tye (Sage) on May 21, 2001 at 23:27 UTC
    package foo; use vars '$foo'; sub foo1 { my $prev= $foo; $foo= shift if @_; return $prev; } { my $foo; sub foo2 { my $prev= $foo; $foo= shift if @_; return $prev; } } my $foo; sub foo3 { my $prev= $foo; $foo= shift if @_; return $prev; }
    There I have three variables all called $foo. But none of them have any effect on the others. $foo::foo only refers to the first one as lexical variables are not "package globals" and so can't be accessed globally using a package name.

    Perl offers no way to prevent random code from creating random variables in any package (even in packages that don't exist yet). However, if you want to trap attempts to use a specific variable, then you can use tie:

    package foo; use vars '$foo'; sub TIESCALAR { return bless {}, foo::ThereIsNoSuchVariable; } tie $foo, 'foo';

            - tye (but my friends call me "Tye")