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

I'm having trouble controlling a module with package variables. The var is declared in the module with use vars and resides in @EXPORT_OK as usual and one of the module subs checks the var to make decisions. When scripts use the module, the first sub call prints a menu and uses the var properly, but when calling other subs via the menu the var is somehow ignored:
use Module; $Module::configvar = 1; print Module::menu(); # <- this works, configvar is set, but # not when invoking other subs from the options in menu().
The var is declared in the module but not defined. Some sub just asks if ($Module::configvar), which works, but only for the call to menu() made from the script. AFAIK the var is not being redefined anywhere in the module and it's not a persistent environment so... I'm stumped.

Hope this is enough information to spot my dumb mistake. I wrote a test module and script which worked as expected: the var was seen by other subs when invoked by the initially called sub. So I seem to know what I'm doing but dunno what's wrong with this module and can't post the actual code. Thanks for your consideration.

Replies are listed 'Best First'.
Re: package variable does not persist
by Corion (Patriarch) on Sep 01, 2018 at 07:23 UTC

    Can you please show us a short subroutine where the configuration variable works and an equally short subroutine where it fails?

    You've shown us the outside of things but not how $Module::configvar is accessed within the subroutines where it fails to do so.

Re: package variable does not persist
by AnomalousMonk (Archbishop) on Sep 01, 2018 at 08:06 UTC

    Further to Corion's post:   Can you show us a Short, Self-Contained, Correct Example that demonstrates the problematic behavior? Just the exercise of preparing the SSCCE may reveal to you the root cause of the problem.


    Give a man a fish:  <%-{-{-{-<

Re: package variable does not persist
by AnomalousMonk (Archbishop) on Sep 01, 2018 at 08:41 UTC

    As a start on an SSCCE, I wonder if something like this might be happening:

    # Module.pm package Module; use warnings; use strict; use vars qw($configvar); sub what_is_configvar { if ($Module::configvar) { return 'true'; } else { return 'false'; } } sub menu { print 'in menu(): ', what_is_configvar(); } sub inModule { print 'in Module: ', what_is_configvar(); } inModule(); 1;
    And then:
    c:\@Work\Perl\monks\Anonymous Monk\1221498>perl -le "use warnings; use strict; ;; use Module; ;; $Module::configvar = 1; ;; Module::menu(); " in Module: false in menu(): true


    Give a man a fish:  <%-{-{-{-<

      This is a good guess, and I think it's noteworthy that this happens even if the variable appears to be being set before use Module:

      $ perl -I. -wMstrict -le '$Module::configvar=1; use Module; Module::menu();' in Module: false in menu(): true

      Because use gets run in an implicit BEGIN block, so the code in Module.pm will always be executed before the code that sets $Module::configvar=1;. One solution is to say BEGIN { $Module::configvar=1; } before use Module;.

      Thank you all for asking the right questions about my somewhat wrongly sought wisdom, sorry about that. AnomalousMonk answered Corion's question for me and this good advice was being followed too: "Just the exercise of preparing the SSCCE may reveal to you the root cause of the problem." and it worked of course. I now understand the problem so the solution is obvious. I knew it was some dumb mistake.

      One thing the use Module line does is check for params and dispatches subs based on them which eventually terminate the process.

      If there are no params the use Module line does no dispatch and the script proceeds to set the package var and call a sub that sees it and all is well.

      If there are params then nothing in the script happens after the use Module line, like setting the package variable, and that was the confusing part.

      Since the use line is indeed hijacking my flow as AnomalousMonk noticed, haukex suggested setting the var in a BEGIN block, and now that I understand the problem it all makes sense and works as expected. Thank you monks!

Re: package variable does not persist
by haukex (Archbishop) on Sep 01, 2018 at 10:36 UTC

    First, make sure you've got warnings enabled everywhere, it'll help you catch typos and other accidents (see also Use strict and warnings):

    $ perl -wMstrict -e '$Module::configvar=0; if($Module::confgivar=1) { print "<$Module::configvar>\n"; }' Found = in conditional, should be == at -e line 1. Name "Module::confgivar" used only once: possible typo at -e line 1. <0>

    If that doesn't help, you can trace when the variable gets set, put the following debug code at the top of your program, above use Module; and anything else that may make use of $Module::configvar. It will show you exactly when values are stored in the variable.

    BEGIN { package LoggingScalar; require Tie::Scalar; our @ISA = 'Tie::StdScalar'; use Carp 'cluck'; sub STORE { cluck "STORE"; shift->SUPER::STORE(@_) } tie $Module::configvar, 'LoggingScalar'; }