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

#!/fellow/monks.pl

I'm finally doing it -- I'm using strict, and it's a real change from what I'm used to ;-) Regardless, I need to use it, and so far it's going ok, except for a few minor issues. Fearless monks, I need advise.

For simplicity, here's a simulation of my problem. Enter the pie script.

#!/usr/bin/perl use strict; my $pie; require "b.pl"; &getpied; print "The pie says : $pie\n";
The pie requires script b.pl
#!/usr/bin/perl use strict; sub getpied { my $pie = "eat me"; } 1;

So, without strict and the 'my' declarations, the script works fine, and the pie says 'eat me', however, when I put the strict stuff in, my variables are no longer portable between libraries.

Fearless monks, do I need to define "use strict" on every perl page, or is one on the main calling page enough? And lastly, how can I get $pie to be portable between the two scripts? Using return is not an option, as I have a whole lot of variables that has to be available in about 8 different scripts.

Thanks!

#!/massyn.pl

Don't -- me without telling me why. If you asked a stupid question, I wouldn't down vote you.

Replies are listed 'Best First'.
Re: 'use strict;' between libraries
by Abigail-II (Bishop) on Jul 16, 2003 at 11:50 UTC
    Uhm, you must see the use of use strict; and my as two unrelated things. use strict; does not mean all your variables need to be lexical, and having lexical variables don't require the usage of strict.

    Your problem comes because you made all your variables lexical. That means, the variables are no longer visible in other files (or blocks, but files are blocks too). Hence, they aren't shared. The variables you want to share need to be package variables. Probably the easiest, and certainly the most common way is the use of the Exporter module.

    Abigail

Re: 'use strict;' between libraries
by davorg (Chancellor) on Jul 16, 2003 at 12:01 UTC

    Most of your problem here is caused by having subroutines that are only called for their side effects on global variables. A better approach would probably be to use subroutines which return values.

    #!/usr/bin/perl # pie.pl use strict; my $pie; require "b.pl"; $pie = &getpied; print "The pie says : $pie\n";

    and

    #!/usr/bin/perl # b.pl use strict; sub getpied { return "eat me"; } 1;

    An even better approch would be to look into turning b.pl into a real module.

    Update: Oops. Just saw the part where you said

    Using return is not an option, as I have a whole lot of variables that has to be available in about 8 different scripts.

    (thanks to Skeeve for pointing it out)

    In that case, you really need to turn b.pl into a module and use Exporter.

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

      Just to let you know why --. He explicitly didn't want to return the value

      > Using return is not an option, as...

      But I have to aggree that it's a better approach to try to use return values or at least give the subroutine a reference to the variable that should be changed.

        Update: This was excessively rude and brutal on my part. Although probably factually accurate, I should have found a more polite way to say this than the method I chose. I'm sure the OP is a good guy whose code does what it's intended to do, whatever issues it might have from a purist's point of view.

        His full statement was:

        Using return is not an option, as I have a whole lot of variables that has to be available in about 8 different scripts.

        He might just as well say:

        I don't want to return variables because I want to write crappy code - I just want to put use strict at the top of the files so it doesn't look like crap, or because it looks cool, or because "everyone says I should".

        He is building a demonic cluster-f***, which will torment him and all who follow.

        And I'm not trying to be mean, but this is not the way to do a project. There is a reason you break things into pieces, but if you're going to use global variables everywhere, <sarcasm>better to have it all in 1 file 10000 lines long, where at least you find all the references to your globals.</sarcasm>.

        --Bob Niederman, http://bob-n.com
Re: 'use strict;' between libraries
by larsen (Parson) on Jul 16, 2003 at 11:55 UTC
    my declares a lexical variable. That is, a variable visible from the point of its declaration to the end of the block where is has been declared. In your case, $pie no longer exists when the control exits from the sub getpied(). On the other hand, in the pie script, $pie exists from its declaratio to the end of the file, and it's visible in the same scope, and only there. But it's another $pie.

    To share variables among files, you have to use global variables.
Re: 'use strict;' between libraries
by Skeeve (Parson) on Jul 16, 2003 at 11:50 UTC
    You are using "local" variables. my $pie is local to your files.

    What you want are globals.

    so use vars qw($pie);

Re: 'use strict;' between libraries
by dragonchild (Archbishop) on Jul 16, 2003 at 13:28 UTC
    There are, essentially, two options open to you to solve your issues.
    1. Don't use strict. This is generally considered poor programming practice for projects you want to have run more than once. However, strict wasn't in Perl 1.0 and large projects were still done.
    2. Rewrite what you're doing.
    The issue is this - to make (what I know) of your project to work under strict, you will seriously cry. In fact, it would take longer to shoehorn strict into your design than it would to rewrite your project to work with strict. A few possible rewrite directions:
    1. Consolidate all the globals into a hash and declare that hash with our or use vars.
    2. Consolidate everything into a Singleton.
    3. Restructure your project so that it doesn't use globals at all.
    That last sounds really hard, but it's just a small shift in your thinking at the base level. Once you make that shift, you'll find it much easier to work with your code because you KNOW exactly what's happening at any given spot. *shrugs* YMMV

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: 'use strict;' between libraries
by bobn (Chaplain) on Jul 16, 2003 at 12:46 UTC

    To amplify a little on what others have said - and this is not said to evade your question - you should NOT be doing what your trying to do, which is sharing varibles across files of a project. To do that they must be globals, and that way lies madness.

    To repeat what others have said, data sent back and forth should be done by passing parameters from the calling to the called (which will usually be transferrred into lexicals within the sub by something like my ( $p1, $parm2, $etc, ) = @_; and returning values from the called to calling.

    By making the file with the subs in it a module, you avoid namespace pollution, which is to say that if the subroutines in a file need to share variables with each other, they are still separate from variables you have inadvertently named the same thing in other modules or in your main program.

    And to answer your last question, use strict;

    works on a lexical scope, which is to say the scope is between the ineermost containg braces, or, at most, the whole of the file, so yes, every file needs use strict.

    Oh, and these 2 files do NOT work as given in the absence of use strict, if you think they do, you're confused. It is the scoping of the "my" variable that prevents the scripts from working, not the use of strict.

    --Bob Niederman, http://bob-n.com
Re: 'use strict;' between libraries
by tcf22 (Priest) on Jul 16, 2003 at 13:33 UTC
    How about using our.
    #!/usr/bin/perl use strict; our $pie; require "b.pl"; &getpied; print "The pie says : $pie\n";
    The pie requires script b.pl
    #!/usr/bin/perl use strict; sub getpied { our $pie = "eat me"; } 1;

    This outputs "The pie says : eat me".

    Also, about using strict, it must be done in every script.
Re: 'use strict;' between libraries
by sgifford (Prior) on Jul 16, 2003 at 15:17 UTC

    The easiest way to fix the use strict issues without changing any other code is to remove both of the my declarations, and to the top of both files add use vars qw($pie).

    Under strict, use vars is how you declare global variables. my declares lexically scoped variables, and the $pie inside getpied is a completely different variable that happens to have the same name.

Re: 'use strict;' between libraries
by Massyn (Hermit) on Jul 17, 2003 at 08:28 UTC

    I'll play with the idea of passing the variables between the libraries using return and ($v1,$v2) = @_;. Please bare with me if I ask questions that would seem ordinary to you. I want to use strict, I want to use a proper programming style. The many years of programming in BASIC (Commodore 64, GWBasic, Turbo Basic, QBasic) has taught me a few bad things, and it is hard to break old habbits.

    Again, thank you for the wise words.