Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

my $var masked across package scope?

by QM (Parson)
on May 09, 2013 at 13:27 UTC ( [id://1032767]=perlquestion: print w/replies, xml ) Need Help??

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

Do my variables ignore package scope?

I have a module with several packages declared in them. Here's a minimal example:

#!/usr/bin/env perl use strict; use warnings; package Foo; my $package = __PACKAGE__; package Bar; my $package = __PACKAGE__;

and perl -c gives:

"my" variable $package masks earlier declaration in same scope at junk +.pm line 9.

Is this expected?

Is there a better solution?

-QM
--
Quantum Mechanics: The dreams stuff is made of

Replies are listed 'Best First'.
Re: my $var masked across package scope?
by choroba (Cardinal) on May 09, 2013 at 13:34 UTC
    Yes, my variables declared at the highest level have file scope. The solution is to use blocks for packages:
    { package Foo; my $package = __PACKAGE__; } { package Bar; my $package = __PACKAGE__; };

    Or, in recent Perls:

    package Foo { my $package = __PACKAGE__; }; package Bar { my $package = __PACKAGE__; }
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
      Thanks.

      I must say, though I don't fully grok the different scopes, my tiny brain wants package scope to be its own lexical scope too. At least, if I redeclare a my variable that exists outside the package scope, I don't want the warning. If I want to access that farther-away variable, I should have that option too, as long as I haven't stepped on it with a closer my. (This is the way it works crossing lexical boundaries, it's just that package isn't a lexical boundary.)

      Are there any benefits to having package not be a lexical boundary? (Just idle curiosity, as there's bleep-all chance of changing it now :D )

      -QM
      --
      Quantum Mechanics: The dreams stuff is made of

        "Are there any benefits to having package not be a lexical boundary?"

        It's sometimes handy to switch package mid-sub...

        use v5.12; use Data::Dumper (); # not importing Dumper function here sub d { package Data::Dumper; # please don't clobber @_ local *Indent = local *Terse = 1; say Dumper(@_); } d [1, 2, 3]; d {foo => 123};

        Also if package touched lexical variables it would probably confuse newbies into thinking that namespaces and lexical scopes have something to do with each other.

        package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
        /div
Re: my $var masked across package scope?
by InfiniteSilence (Curate) on May 09, 2013 at 13:44 UTC

    There's an awesome and often unused tool that comes with perldoc that will just tell you about particular Perl keywords. Using "perldoc -q my" will tell you that,

    A "my" declares the listed variables to be local (lexically) to the e +nclosing block...
    So, enclosing your variable declarations inside of different blocks resolves the problem. Here's a more involved example:
    #!/usr/bin/env perl + + use strict; use warnings; package Foo; { my $package = __PACKAGE__; sub new { return bless {'PACKAGE'=>$package} } } package Bar; { my $package = __PACKAGE__; sub new { return bless {'PACKAGE'=>$package} } } package main; my $foo = Foo->new; my $bar = Bar->new; print $foo->{'PACKAGE'}; print qq|\n\n|; print $bar->{'PACKAGE'};

    Celebrate Intellectual Diversity

Re: my $var masked across package scope?
by tobyink (Canon) on May 09, 2013 at 15:26 UTC

    my declares a lexically scoped variable. A lexical scope continues until the closing brace (}) that ends the block it was defined in, or until the end of the file, whichever comes first.

    { package Foo; my $foo = 1; package Bar; # can still see $foo here package Baz; # can still see $foo here } # cannot see $foo any more

    While our variables are associated with a particular package, they too are lexically scoped:

    { package Foo; our $foo = 1; # $foo is an alias for $Foo::foo package Bar; # $foo is still an alias for $Foo::foo here package Baz; # $foo is still an alias for $Foo::foo here } # cannot see $foo any more

    For this reason, if you're defining multiple packages in the same file, it's a good idea to define them each within their own {...} block, so they don't accidentally leak variables. (Of course, sometimes - probably quite rarely - you'll actually want to share a lexical variable between the packages, in which case, just declare it right at the top before the first opening brace.)

    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
      From your other post:
      If package touched lexical variables it would probably confuse newbies into thinking that namespaces and lexical scopes have something to do with each other.
      and above:
      If you're defining multiple packages in the same file, it's a good idea to define them each within their own {...} block, so they don't accidentally leak variables.
      Yes, agreed. In the future I'll be putting lexical scope around my package scopes. And in the event I want a variable private to the package scope, I can use my, and because of my improved practice, not worry about it. (Now is a good place for the cargo cult folks to interject.)

      I was wondering though, why both scope types have to be completely independent? Or rather, why we have to carry around the idea of multiple types of scope boundaries in relation to lexical variable? In my own head, a scope boundary is always a lexical scope boundary. Wrong as it is, I want to think that my $var declared inside a package scope isn't implicitly available outside. If I need it available outside, I should declare it outside, or otherwise arrange for it to be visible.

      I'm never concerned about variables leaking in, and often depend on it, so it seems this small conceptual tweak would save me some register space in my head when writing code. (It's harder to keep track of two similar but distinct items, compared to two completely different items. Compare "the electron and the proton" vs. "this electron and that electron" -- if only electrons came in colors.)

      If the idea of "a package scope boundary also being a lexical scope boundary" were actually implemented, would it cause any programs to break? (And if it did, would they have been correct programs anyway?) I'm not saying it's a trivial change, as suddenly package scope is a lexical scope. So, theoretically speaking, are there any downsides to proper nesting of package and lexical scope?

      -QM
      --
      Quantum Mechanics: The dreams stuff is made of

        "If the idea of "a package scope boundary also being a lexical scope boundary" were actually implemented"

        It kind of already is implemented in Perl 5.14, albeit with a change in syntax:

        package Foo { my $foo = 123; package Bar { # can still see $foo } } package Baz { # cannot see $foo }

        "would it cause any programs to break?"

        The change of syntax makes it opt-in. Use the old syntax; get the old behaviour. Thus nothing needs to break.

        "would they have been correct programs anyway?"

        Yes; it's perfectly reasonable to want to share a lexical variable between different packages. It's not a common need, I grant you. And if it were forbidden the sky would not fall; workarounds would be possible. But the ability to share a lexical variable can, in some cases result in much cleaner code than would be possible without it.

        package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name

        :)

        If the idea of "a package scope boundary also being a lexical scope boundary" were actually implemented, would it cause any programs to break?

        Yes, changing the rules breaks programs

        (And if it did, would they have been correct programs anyway?)

        Yes, they would have been correct, if they did what they were supposed to do :)

        I'm not saying it's a trivial change, as suddenly package scope is a lexical scope. So, theoretically speaking, are there any downsides to proper nesting of package and lexical scope?

        Every programming language with a  class keyword uses parens to make scope, not the class keyword

        We already have proper nesting of package and lexical scope, so it could be said its a waste of time to redefine proper/nesting/scope rules for everyone

        But, a pragma can be created to turn package foo; ... package bar; into package foo;{...} package bar; {...} , using one of those magical B::Hooks:: modules

Re: my $var masked across package scope?
by Random_Walk (Prior) on May 09, 2013 at 13:33 UTC

    Yes, this is expected.

    Update

    but my explanation was wrong. Please see the following node for enlightenment.

    Cheers,
    R.

    Pereant, qui ante nos nostra dixerunt!
      my variables are kept in a table local to the package in which they are created
      Not true. There is block scope and file scope, no package scope. See also Packages, scope, and lexical variables.
      لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (3)
As of 2024-04-19 22:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found