Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

our scope and packages

by jfrm (Monk)
on Aug 28, 2008 at 22:50 UTC ( #707620=perlquestion: print w/replies, xml ) Need Help??

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

I am deeply frustrated and it's not just because I'm stuck in this monastery with a bunch of bald blokes.

I'm never too good with scoping and I'm sure this is a dumb question but here goes. I've been using a hash for a long time within perl files in my webroot/cgi-bin directory that I initialise in the opening file with our %prod; Then in other files that are "use"d, I declare our %prod; and happily use it.

Now I've been gradually turning object oriented in my old age and for the first time, I want to use %prod in a package file called webroot/MG/

Now when I do our %prod; and try to use it, I can't - it isn't populated. Presumably %prod is no longer in scope - perhaps due to the location of the file not being in the same directory? Anyway, please please can someone tell me how I can access %prod from my package. There seems to be very little on the function "our" in manuals and tutorials.


Replies are listed 'Best First'.
Re: our scope and packages
by tilly (Archbishop) on Aug 28, 2008 at 23:01 UTC
    Your problem is that Perl scopes according to packages. It is not that %prod is in a different file. It is that it is in a different package. The cheesy solution is to just make %prod in your current package be the copy in the root package, which is called main:
    *prod = \%main::prod; our %prod;

      Thank you; it all sounds highly feasible. However, this is unfamiliar territory. Should I be putting this statement *prod = in the originating file (it isn't an OO package - at least I don't think it is) where %prod is populated or should I be putting it in the package that currently can't access it? Or both?

      thanks a lot for your help.

        In the package that currently can't access it.

        Actually the really right way to do it is to move %prod into a configuration module that might look like this:

        package My::Configuration; use strict; use Export qw(import); our @EXPORT_OK = qw(%prod); our %prod = ( ... ); 1;
        and then somewhere in main and in your other package insert the line:
        use My::Configuration qw(%prod);
        Doing that you won't even need the our declaration because importing it declares it.
Re: our scope and packages
by ikegami (Patriarch) on Aug 28, 2008 at 23:09 UTC

    our %prod; creates an alias named %prod to the variable %PKG::prod, where PKG is the package in which the our is located.

    The alias exists until the end of the lexical scope (curlies or file).

    # package ModuleA; our %prod; # %prod is aliased %ModuleA::prod package ModuleA::Helper; # %prod is still aliased %ModuleA::prod 1;
    # package ModuleB; our %prod; # %prod is aliased %ModuleB::prod 1;
Re: our scope and packages
by betterworld (Curate) on Aug 28, 2008 at 23:09 UTC

    I'd suggest using Exporter:

    # package Module1; our %variable; use base 'Exporter'; our @EXPORT_OK = qw(%variable); %variable = ( foo => "foo" ); # package Module2; use Module1 qw(%variable); print $variable{foo};

    However, if you plan to use this variable to exchange data between the modules, I'd suggest using subroutine arguments instead.

Abandon "our" declarations (was: Re: our scope and packages)
by Narveson (Chaplain) on Aug 29, 2008 at 05:00 UTC
    There seems to be very little on the function "our" in manuals and tutorials.

    This observation is correct, and that's because there are few if any projects that are not improved by a global s/our/my/.

    Of course that will break your existing system of letting everybody share the same global variable. This is generally considered a good thing.

    In the file where you declare and populate my %prod, follow it up with an offer to share:

    sub get_prod_ref { return \%prod; }

    and now let client files say

    use My::Configuration; my $prod_ref = My::Configuration::get_prod_ref(); # or if you prefer my %prod = %{ My::Configuration::get_prod_ref() };
      there are few if any projects that are not improved by a global s/our/my/.

      You can easily support use My::Configuration qw( %prod );. Although the basic doesn't support exporting of lexicals, it is dead easy to support that yourself and I strongly suspect that at least one of the "better exporter than Exporter" modules on CPAN is already written to allow you to export lexicals as well.

      But just to prove how easy it is, if you only have one variable to potentially export, I roll my own exporter as you watch:

      package My::Config; use strict; my %prod = ( foo => 'bar' ); my %export= ( '%prod' => \%prod ); sub import { my ( $me, @syms )= @_; my $caller= caller(); for my $sym ( @syms ) { my $ref = $export{$sym}; if ( ! $ref ) { require Carp; Carp::croak( __PACKAGE__, " does not export $sym\n" ); } $sym =~ s/^[\$\@\%]//; no strict 'refs'; *{ $caller.'::'.$sym }= $ref; } }

      Heh, that one isn't even limited to just exporting one variable (it doesn't support exporting groups of symbols yadda, of course).

      - tye        

        It is hard to justify such code in any serious context.

        This is written to be an object method but it effects the object's package namespace not the object.

        This is code that should not be applied to mature code since the My::Config module needs be invaded and all the client code needs to be altered to use it. If there is already a My::Config::import function, it would be better to change the lexicals to package variables inside My::Config.

        If writing new code, such misuse of lexicals is perverse. ... That is the thing I like about it. Ahh.

        Be well,

Re: our scope and packages
by cbrandtbuffalo (Deacon) on Aug 29, 2008 at 12:04 UTC
    Intermediate Perl spends quite a bit of time discussing packages and how they are used with OO in perl. The info there would give you good context for the issues you were running into and why the various solutions posted here solve the problem.

Log In?

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

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (3)
As of 2023-10-03 03:17 GMT
Find Nodes?
    Voting Booth?

    No recent polls found