Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

using main package variables within a module

by fireartist (Chaplain)
on Jun 17, 2002 at 14:49 UTC ( #175087=perlquestion: print w/replies, xml ) Need Help??

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

I'm creating my first module, to reduce code redundancy in a project with several scripts.
I have read perldocs perlmod perlmodlib the Simple Module Tutorial and done a search on Google's advanced search, but haven't figured out yet what's going wrong.

I want a sub-routine in my module to access variables in main (and I would also like to be able to access variables in my config file with calls such as $conf->{'db_database'} but that isn't working either.

test.pl
#!/usr/bin/perl -wT use strict; use lib '/home/4220/straitwa/www.straitway.net/shop_34/lib'; use Shop; my (%conf, $conf, $dbh, $sth, $rc, @db_conf); #open the config file and parse it unless ($conf = do ('/home/4220/straitwa/www.straitway.net/shop_34/con +f.pl')) { die ("Could not open config file"); } my $one = $conf->{'db_database'}; print "Print - ", $one, " - from the main package\n"; Shop::db_connect;
The module Shop.pm
package Shop; use strict; use Exporter; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = 1.00; @ISA = qw(Exporter); @EXPORT = (); @EXPORT_OK = qw(db_connect); sub db_connect { print "Print - ",$main::one, " - from the Shop package\n"; } 1;
The resulting output is
Print - straitway_1 - from the main package Use of uninitialized value in print at /home/4220/straitwa/www.straitw +ay.net/shop_34/lib/Shop.pm line 13. Print - - from the Shop package
Any pointers? Thanks.
Edited by boo_radley : corrected anchor tag

edited - 17 June 2002 (footpad): Corrected another A tag problem.</small

Replies are listed 'Best First'.
Re: using main package variables within a module
by SarahM (Monk) on Jun 17, 2002 at 16:10 UTC
    The problem you are having is with scope. Since you are making $one a local variable, it is only available withing the main package and the main code. So when another package accesses $main::one, it is actually getting the global version of the variable, which is undefined. At least this is how it was explained to me. If someone knows better, be sure to tell us!!!!

    To get you code to work, you can do one of two thing.
    1. Make $one a global. I don't like this idea, but it is there.
    2. Use a typeglob so the variable is in scope. This is a much cleaner way to deal with the problem. To use a typeglob, you would change your code to look like this:

    package Shop; use strict; use Exporter; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = 1.00; @ISA = qw(Exporter); @EXPORT = (); @EXPORT_OK = qw(db_connect); sub db_connect { *one = *main::one; print "Print - ",$one, " - from the Shop package\n"; } 1;
    P.S. Why are you accessing vars in main anyway? You may want to reconsider your design to use an object and have your main script set parameters on that object. Or you should have the variable be in your package, and then export or typeglob it to main's name space.
Re: using main package variables within a module
by cLive ;-) (Prior) on Jun 17, 2002 at 16:09 UTC
    I think you're going to make things worse in the long term if you try to put references to vars in main:: namespace.

    Is there any reason you can't put the conf vars in their own module and then start the other modules with:

    use Conf;

    Look into using AUTOLOAD in the Conf module, and then:

    # change my $one = $conf->{'db_database'}; # to my $conf = new Conf; my $one = $conf->db_database;
    I'll leave you to work out the AUTOLOAD and 'new' methods for your instance :)

    .02

    cLive ;-)

    --
    seek(JOB,$$LA,0);

Re: using main package variables within a module
by DamnDirtyApe (Curate) on Jun 17, 2002 at 18:13 UTC

    You may find some answers in Coping with Scoping.

    That being said, I really think it's a bad idea for your package to try and access variables in main. If a sub in another package needs some information, then pass it to the sub.

    One the last line of your test.pl file, what would be the harm in calling your sub like so:

    Shop::db_connect( \%conf ) ;

    And then changing your Shop_db_connect function to read:

    sub db_connect { my $conf = shift ; print "Print - ", $conf->{'db_database'}, " - from the Shop package\n"; }

    I don't know if you are able to access your main varables the way you're trying to, but if you can, you may be leaving the door open for unexpected side effects with your variables in main. If a sub, any sub, needs something that's not supposed to be global, then just give it to it. Don't expect it to come get it itself. If you need the sub to be able to change values you give it, pass them by reference like so:

    #! /usr/bin/perl use strict ; use Data::Dumper ; my %conf = ( DB_NAME => 'DB01' ) ; pass_by_reference( \%conf ) ; print Dumper( \%conf ) ; sub pass_by_reference { my $conf = shift ; $conf->{DB_NAME} = 'DB03' ; }

    Even this can be a little messy, because from the calling package there's no way to know what's happening to %conf. But, it's a whole lot cleaner than accessing global variables.


    _______________
    D a m n D i r t y A p e
    Home Node | Email
      Rest assured that the only reason I had that dirty $one in global was because I stripped the script to the bare minimum to try and figure out what was going wrong.

      The only globals the entire script has are $dbh, $sth, $rc for database calls, and $conf and %conf.
      $conf contains the hash from my config file and %conf is my CGI params grabbed from CGI->vars.

      I think for now I'm going to experiment with both cLive ;-)'s suggestion of containing my config data in a module of it's own, and I think I'll also try out setting the $conf reference to a global.
      my $main::conf; unless ($::conf = do ('/home/4220/straitwa/www.straitway.net/shop_34/c +on +f.pl')) { die ("Could not open config file"); }
      I'd appreciate anybody's opinion on whether having five global variables is a bad thing. - I mean, should I really aim to have no globals or is that overkill.

      I realise that my whole problem here was my misunderstanding that my $foo declared in the main package doesn't make it the same as $main::foo
      I greatly appreciate everyone's help here,
      Thanks!

      fireartist
Re: using main package variables within a module
by fireartist (Chaplain) on Jun 17, 2002 at 14:53 UTC
    (sorry about the above error, I accidentally hit 'submit' instead of 'preview')
    But I know you're all forgiving monks!...
Re: using main package variables within a module
by dda (Friar) on Jun 17, 2002 at 15:57 UTC
    If you change my $one to $main::one, it will work, but I don't like this solution. :)

    --dda

      I don't like it either ;)

      I'm really wanting to understand why my $one isn't working, I think it's in scope!

      As I explained above, I'll also be wanting to access variables from my config file - something like below, expect this doesn't work.

      test.pl
      #!/usr/bin/perl -wT use strict; use lib '/home/4220/straitwa/www.straitway.net/shop_34/lib'; use Shop; my ($conf); #open the config file and parse it unless ($conf = do ('/home/4220/straitwa/www.straitway.net/shop_34/con +f.pl')) { die ("Could not open config file"); } Shop::db_connect;
      Shop.pm
      package Shop; use strict; use Exporter; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = 1.00; @ISA = qw(Exporter); @EXPORT = (); @EXPORT_OK = qw(db_connect); sub db_connect { print $conf->{'db_database'}; } 1;
      conf.pl
      { db_database => 'straitway_1', }
      What I'm wanting is the module Shop.pm to use the data in conf.pl, but I'm getting the error message
      Global symbol "$conf" requires explicit package name at /home/4220/str +aitwa/www.straitway.net/shop_34/lib/Shop.pm line 13. Compilation failed in require at ./test.pl line 4. BEGIN failed--compilation aborted at ./test.pl line 4.
        I'm really wanting to understand why my $one isn't working, I think it's in scope!

        But it's not in scope. :)

        The problem you're having is because you're trying to access a lexical (my) variable outside of its lexical scope. That's a no-no. Only package variables can be accessed via their full package name.

        As an example of why this is, consider the following:

        if ($foo == 3) { my $bar = 1; } else { my $bar = 1; }

        Here you've got two distinct $bar's, each one in a different lexical block. If you said $main::bar, and Perl allowed outside access to lexicals, how would Perl know which $bar to give you? It can't. That's why $main::bar can only refer to a package global. Since you're using strict, you have to declare it with a fully qualified name. That means you'll need to call it $main::bar (or $::bar, for short) when you declare it in test.pl.

Re: using main package variables within a module
by gumby (Scribe) on Jun 17, 2002 at 14:53 UTC
    Yikes! Close those tags!

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (5)
As of 2021-07-29 11:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?