Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Is this a bug in Perl scope?

by Zarabozo (Acolyte)
on Jul 22, 2012 at 13:32 UTC ( [id://983064]=perlquestion: print w/replies, xml ) Need Help??

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

Hello,

I'm having an issue in a file that declares more than one package. It all boils down to the following example:
package one;
use strict;
use warnings;
my $var = 1;

package two;
use strict;
use warnings;
my $var = 5;

package main;
use strict;
use warnings;

print "$var\n";
Which gives the following warning an answer:
"my" variable $var masks earlier declaration in same scope at test.pl line 9.
5
1) Shouldn't the "package" mean a different scope and NOT produce the 'mask earlier declaration' warning?

2) Shouldn't the last line produce an error instead of printing "5" since $var was never defined on 'main' and all packages use strict?

I tried this on Perl 5.010 and Perl 5.014 with the same result.

This really scares me. :-|

Francisco

Replies are listed 'Best First'.
Re: Is this a bug in Perl scope?
by Corion (Patriarch) on Jul 22, 2012 at 13:35 UTC

    No. package only declares a new package, it does not end the lexical scope of the previous package. The $var you use after the package main statement is the lexical $var that you declared after the package two; statement.

      Ok, then, if the scope is the same:

      1) Why the variable doesn't really get redefined?
      2) Why 'my' produces a warning and 'our' doesn't? (if you use 'our' 2 times in the same package for the same variable, you DO get a warning)

      On the following code, you get the 'mask earlier declaration' warning twice. Yet, it's not the same variable since each one keeps their current value. If you change "my" for "our", you don't get any warning about redefining the same var:
      package one;
      use strict;
      use warnings;
      my $var = 1;
      sub tell {
      	print "$var\n";
      }
      
      package two;
      use strict;
      use warnings;
      my $var = 5;
      sub tell {
      	print "$var\n";
      }
      
      package main;
      use strict;
      use warnings;
      my $var = '20';
      sub tell {
      	print "$var\n";
      }
      
      one::tell();
      two::tell();
      main::tell();
      
      Produces the following output:
      "my" variable $var masks earlier declaration in same scope at test.pl line 12.
      "my" variable $var masks earlier declaration in same scope at test.pl line 20.
      1
      5
      20
      

        our and my are very different things. our creates an alias for a global variable. my creates a name and a value.

        The only thing the two have in common is that the alias created by our and the name created by my are valid within the current scope.

        As Perl assumes that you don't want to shadow the name created by a my statement, because it likely is the only way to get at its associated value, it warns you about this.

        I don't know why our doesn't always warn, but that may be because I don't use our. I prefer the vars pragma, which only creates the values within the package, which seems to me what you expect.

        I think the main issue for you is that package does not end a previous lexical scope. Some people try to manage that by using the following syntax:

        package foo { # this block provides lexical scope for package foo ... }; package bar {# this block provides lexical scope for package bar ... };

        I don't see much use in that because my packages are either so large that they live in separate files or are so tiny that they only consist of configuration data masquerading as code. In neither case, lexical scope plays much of a role on the package scope.

        By the way (though not a part of your stated problem), tell is a native function name... and thus a poor choice for the name of a sub.

        perdoc -f tell will give you the details; in short, tell can help you find your location in a filehandle.

Re: Is this a bug in Perl scope?
by trwww (Priest) on Jul 23, 2012 at 21:29 UTC

    This behavior is documented very clearly:

    perldoc -f my A "my" declares the listed variables to be local (lexically) to the enclosing block, file, or "eval".

    There no such thing as a "package scope". To do what you want you'd have to use blocks:

    $ perl use strict; use warnings; { package one; my $var = 1; } { package two; my $var = 5; } package main; print "$var\n"; Global symbol "$var" requires explicit package name at - line 16. Execution of - aborted due to compilation errors.

    Also, FYI warnings and strict are filescoped also if they aren't in a more specific container.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://983064]
Approved by Corion
Front-paged by kcott
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (5)
As of 2024-04-23 11:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found