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

global module variable are imported copies?

by perlnub (Initiate)
on Sep 17, 2012 at 13:57 UTC ( #994043=perlquestion: print w/ replies, xml ) Need Help??
perlnub has asked for the wisdom of the Perl Monks concerning the following question:

Hi, Im starting out with Perl, and want a global variabel which is set at the start of the script and used by multiple .pl files. So I want a second script to be able to read the newly set global variable set by the first script. my setup is almost complete, but it seems like the 'use' statement imports me a copy of the module variable, not the actual current value present in the other script module import which is the callee. How to achieve the desired behaviour? I do not want to give up 'use strict' because I believe it is there for a reason ;-) and I tried with global variables but all in vain. the module:
#!/usr/bin/perl package subs::utils; use strict; use warnings; BEGIN { require Exporter; # set the version for version checking our $VERSION = 1.00; # Inherit from Exporter to export functions and variables our @ISA = qw(Exporter); # Functions and variables which are exported by default # exported only if fully qualified our @EXPORT_OK = qw($henky); } our $henky = "henky_init"; END { } 1; # return a true value, standard module behaviour
first.pl:
use subs::utils; print "now1: " . $subs::utils::henky . "|\n"; $subs::utils::henky = "spanky"; print "now2: " . $subs::utils::henky . "|\n";
second.pl (called by first.pl):
use subs::utils; print "now3: " . $subs::utils::henky . "\n";
gives output:
now1: henky_init| now2: spanky| now3: henky_init
If I look at the output of 'use' I think I understand this doesnt work:
BEGIN { require "My/Module.pm"; My::Module->import(); }
How to get: 'now3: spanky|' in second.pl ?? Many thanks, the perl newb,

Comment on global module variable are imported copies?
Select or Download Code
Re: global module variable are imported copies?
by kennethk (Monsignor) on Sep 17, 2012 at 14:17 UTC
    The issue here is that you are expecting persistence, whereas normally your environment gets reset for each execution of perl. If you want your variable value to persist beyond a single run, you'll need to store the value in a place that persists beyond a single execution of the script; this spec is usually hit using files for storage. So maybe you'd want something like:
    #!/usr/bin/perl package subs::utils; use strict; use warnings; BEGIN { require Exporter; # set the version for version checking our $VERSION = 1.00; # Inherit from Exporter to export functions and variables our @ISA = qw(Exporter); # Functions and variables which are exported by default # exported only if fully qualified our @EXPORT_OK = qw($henky); } my $filename = 'store.txt'; our $henky; if (open my $fh, '<', $filename) { local $/; $henky = <$fh>; } else { $henky = "henky_init"; } END { open my $fh, '>', $filename or die "Storage failed: $!" print $fh $henky; } 1; # return a true value, standard module behaviour

    Note that this may cause some weird behavior if you don't expect a truly persistent type of behavior. Also note that my file name is unqualified, and is thus sensitive to your choice of working directory. If this is a problem, you'll need to give it a full path that everyone who might use the module has read permission on.


    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

Re: global module variable are imported copies?
by BillKSmith (Chaplain) on Sep 17, 2012 at 15:33 UTC

    Although not exactly what you want, a viable workaround is to import a copy of a reference. Of cource, you must dereference it each time you use it.

    Bill
Re: global module variable are imported copies?
by Anonymous Monk on Sep 17, 2012 at 19:14 UTC
Re: global module variable are imported copies?
by tobyink (Abbot) on Sep 17, 2012 at 19:29 UTC

    How exactly is first.pl calling second.pl? There are several ways this can be accomplished. If you're using system(), exec(), qx() or backticks, then they've got no chance of sharing variables. (Not the way you're doing it anyway.) With do "second.pl" you'll fare better.

    But really, I believe you should rethink your approach to structuring your code. Generally speaking a single process should be a single ".pl" file; ideally only a few lines long. The bulk of code should be organised into reusable modules.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
      Thanks guys, Well, the first .pl actually calls a bash script which in turn calls the second .pl script. This is due to bash support for this framework. Quite logical that the Perl variables are not persistent... A file based approach is what I was trying to avoid : ) Maybe I can look into environment variables, but all sound hacky and I should reconsider the whole global idea as usual. Thanks.
        A more significant question in my mind is why is the intermediate bash shell necessary? Can you rework the logic so that perl calls bash and then, once bash finishes, continues on its merry way?

        In this context, my solution won't work because it only serializes the value upon exit. You should probably write an accessor method in your globals module so that, regardless of how your export scheme works, changes to your variable are propagated.

        At the end of the day, the methods that sound cleanest to me are command line parameters or environment variables, depending on some secondary concerns like existing codebase. Setting environmental variables in Perl is as simple as modifying/reading the %ENV hash; e.g. perl -e '$ENV{HELLO} = "Hi\n"; system(q{echo $HELLO})' So, modifying my code from above, your module might read

        #!/usr/bin/perl package subs::utils; use strict; use warnings; BEGIN { require Exporter; # set the version for version checking our $VERSION = 1.00; # Inherit from Exporter to export functions and variables our @ISA = qw(Exporter); # Functions and variables which are exported by default # exported only if fully qualified our @EXPORT_OK = qw(get_henky set_henky); } $ENV{HENKY} //= "henky_init"; sub get_henky {return $ENV{HENKY}}; sub set_henky {$ENV{HENKY} = shift}; 1; # return a true value, standard module behaviour

        Update: But I neglected to point out that changes to the variable won't propagate back up the shells, since a change in a child's environment don't affect the parent. For example: perl -e '$sq=chr 39; $ENV{HELLO} = "Hi\n"; system(qq|perl -e ${sq}print \$ENV{HELLO};\$ENV{HELLO} = "Yo\n";print \$ENV{HELLO}${sq}|); print $ENV{HELLO};' outputs

        Hi Yo Hi

        #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (7)
As of 2014-08-27 10:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (236 votes), past polls