Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Re: How to import "global" variables into sub-scripts from main script?

by bliako (Monsignor)
on Mar 23, 2021 at 10:53 UTC ( [id://11130190]=note: print w/replies, xml ) Need Help??


in reply to How to import "global" variables into sub-scripts from main script?

Placing all your "shareable" variables in a package (which is not OO) can help you to save lines of code (at least). Btw, making money from code has nothing to do with keeping your mind hussle-free and your program maintainable:

# package to group all constant, read-only vars like $DEBUG # file is Constants.pm and can be placed in same dir as main script # or in a './lib' dir, make sure to adjust 'use lib...' in any subscri +pt it uses it package Constants; use strict; use warnings; # boilerplate use Exporter; our @ISA = qw/Exporter/; # add here all the variables you want exported our @EXPORT = qw/$CON1 $CON2 $DEBUG/; our $CON1 = 'a constant'; our $CON2 = 'another constant'; our $DEBUG = 1; 1;
# usage from a so-called sub-script use strict; use warnings; # this is where the Constants.pm file resides relative to the path of +the subscript. # good practices exist for where to place these files, this is just fo +r demo use lib 'lib'; use Constants; print "Debug: $DEBUG\n";
# test.pl to demo the whole setup # run as perl -I. test.pl use strict; use warnings; do 'lib/subscript.pl'; die "failed $@" if $@;

In this way you will at least save repeating the our $DEBUG; etc... lines in each of the sub-scripts. (and changing all the subscripts whenever you add a new constant)

I used the word constant but nothing stops you from modifying those "shareable" variables in package Constants, i.e. use them as read-write without any code change above (if you do then perhaps change the filename to 'Shareable.pm' just to be consistent). Caveat: if you want to add one more worries to your head then do that by all means. AFAIC I try to be as lazy as possible and keep my brain free from keeping track who wrote what and where and in which order. As a first step I would place these variables in a package like above, as a second step I would go OO if they had to be read-write. OO is nothing scary, at least in Perl. It's the best way to encapsulate all your data and keep track of who modifies them. The usual way is to create a function to read and modify these variables, for example:

package Sharedvariables; use strict; use warnings; sub new { my $class = shift; my $self = { # store here all the variables you want to share with an initial + value 'DEBUG' => 1, }; bless $self, $class; return $self; } # my ($class, $params) = $@; # return bless {} => $class; sub debug { my $self = shift; # optional boilerplate to keep track who called us and from where: my $parent = (caller(1))[3]; if( ! defined($parent) ){ $parent = 'ma +in' } my $whoami = ( caller(0) )[3]; # optional parameter for setting the $DEBUG to a new value # if this new-value is absent the we just return current value of $D +EBUG my $newvalue = shift; if( defined $newvalue ){ warn "$whoami (via $parent) : modifying DEBUG from ".$self->{'DEBU +G'}." to $newvalue"; $self->{'DEBUG'} = $newvalue } return $self->{'DEBUG'} } 1;
# test it use strict; use warnings; use lib 'lib'; use Sharedvariables; my $SVars = Sharedvariables->new(); print "DEBUG: ".$SVars->debug()."\n"; $SVars->debug(42); print "DEBUG: ".$SVars->debug()."\n";

And here is a version which requires minimal maintentance, you don't have to modify Sharedvariables.pm if you need to add extra variables:

package SharedvariablesM; use strict; use warnings; sub new { my $class = shift; my $self = { # we store here all shared variables, but this is done automatic store => {} }; bless $self, $class; return $self; } sub value { my $self = shift; my $name = shift; # optional parameter for setting the $DEBUG to a new value # if this new-value is absent the we just return current value of $D +EBUG my $newvalue = shift; # optional boilerplate to keep track who called us and from where: my $parent = (caller(1))[3]; if( ! defined($parent) ){ $parent = 'ma +in' } my $whoami = ( caller(0) )[3].'()'; my $itsnewname = ! exists $self->{'store'}->{$name}; if( defined $newvalue ){ if( $itsnewname ){ warn "$whoami (via $parent) : creating new variable '$name'..." } else { warn "$whoami (via $parent) : modifying '$name' from ".$self->{' +store'}->{$name}." to $newvalue"; } $self->{'store'}->{$name} = $newvalue } elsif( $itsnewname ){ die "$whoami (via $parent) : you are creating a new shared varia +ble named '$name' without a value unless you have the variable name w +rong!" } return $self->{'store'}->{$name} } # clone ourselves and return new object sub clone { my $self = shift; my $aclone = SharedvariablesM->new(); for my $name (keys %{$self->{'store'}}){ $aclone->value($name, $self->value($name)); } return $aclone } sub toString { my $self = shift; my $ret = __PACKAGE__." here is what I store:\n"; for my $name (sort keys %{$self->{'store'}}){ $ret .= $name . '=>' . $self->{'store'}->{$name} . "\n" } return $ret; } 1;
# and here is a test usage use strict; use warnings; use lib 'lib'; use SharedvariablesM; my $SVars = SharedvariablesM->new(); for (qw/var1 var2 var3/){ $SVars->value($_, $_); } print $SVars->toString(); my $clone = $SVars->clone(); print $clone->toString();

disclaimer: scripts are unpolished and not all cases tested. If and when you change your mind about Programming then we can talk further.

5' Edit: The OO way offers you some more advantages: 1) by cloning the object holding the variables you can keep different copies of these variables for testing purposes. A deep clone must be done if you keep anything more complex than scalars. 2) You can pass the variables object to each sub that needs to read configuration etc. And it's easy to save (serialise) the object to disk and reload it for the next run in order to remember state. Again, without you making any changes when you add an extra variable.

bw, bliako

Replies are listed 'Best First'.
Re^2: How to import "global" variables into sub-scripts from main script?
by Polyglot (Chaplain) on Mar 23, 2021 at 13:48 UTC

    Bliako, thank you. While some here seem bent on forcing me into their mold, or just writing me off and voting me down, you have gone the extra mile to give me a truly useful set of suggestions. While I appreciate the time you spent on all of it, I will likely only be able to implement your first suggestion--that of putting variables into a package and calling that. THAT is something I never knew was possible before, and that sounds like a perfect solution in my use case. I wonder why no one else does it this way or bothered to suggest this possibility. Thank you so much!

    Really, I wish I could do OO programming. I've tried. I've read the chapters on it in "Programming Perl" (Third edition) multiple times, and have made attempts at using it, only to meet with total failure. My syntax errors simply follow my general lack of understanding. It's always been above me. Perhaps if I had an excellent teacher who could once explain it for me in a way that made sense to me, it might be different--but, just like math, the typical case is that the teacher has almost a language and logic of his/her own--one that is too esoteric for many minds. I have managed to use the my $something = $cgi->param('something'); method from the CGI module, but many other modules are too hard for me to grasp. When one needs to start escaping or doubling the "funny characters" in front of the variables, or start using those "->" references, that's usually where I get lost--I no longer have any idea when to use which form.

    But I think I will put that Variables.pm file to practice shortly! (I'd always put all of that at the top of my main script, but it makes a large chunk of material to have to scroll past every time I want to navigate between the required/used files and the code.)

    Blessings,

    ~Polyglot~

      But I think I will put that Variables.pm file to practice shortly

      right but beware that there may be dragons if you modify those variables in subscripts. There may be cases (which I am not aware of, I am not a Perl expert) where changing a package variable will not be reflected to other users of said package (e.g. one of your various subscripts). For read-write variables it's not a good way and I will not use myself.

      some here seem bent on forcing me into their mold

      Oh come on! (respectfully said). From my experience this is hardly the case with PM (compare to Stack overflow by posting this exact question there -- even your super-ground -- good story btw -- will not protect you from the flaming lightnings they will throw at you). Perl is a fertile ground for TIMTOWTDI and Perl culture preaches it. Perl allows you to do a lot of things, even shooting your foot, some people, understandably frown on extremely un-productive or buggy solutions which can lead to future problems (e.g. maintainability). If I may say so (and I don't wish to start a conversation about this side-issue): saying that your case is special because you are the only maintainer, is not an argument to the good points presented here (about general programming practices at least). You are offered good solutions which require that you change some of your programming habits, "change gear", "grow up" as a user of a programming language. Case-in-point is OO (actually the free style of Perl OO). It can reduce code-lines (which you are interested) tremendously by re-using code, it can encapsulate data and transformations which will make your code more maintainable, easier to handle. It does not require super-human abilities but it requires to program along certain "molds". And btw the -> is used just as you will be using it in a hashref (which essentially is what an OO object is, a mere hashtable with data AND subs as values). Try posting a question about OO and see what happens.

      bw, bliako

        > There may be cases (which I am not aware of, I am not a Perl expert) where changing a package variable will not be reflected to other users of said package

        Do you mean mod_perl and similar parallel preloading environments?

        map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (3)
As of 2024-04-26 04:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found