in reply to Re^2: global var
in thread global var

To clarify (I hope) a few things about "use xxx;"
use xxx; #imports all of the symbols in @EXPORT use xxx (); #imports none of the symbols in @EXPORT #this empty list is the same as: (updated) #BEGIN { require Module } use xxx qw(OpenConnection $LoggedOn_user_id); # imports # all of the symbols in @EXPORT AND subroutine OpenConnection # AND the scalar $LoggedOn_user_id from @EXPORT_OK
Update: Another attempt at explaining "use".
Case 1: A plain use xxx; #imports all of the symbols in @EXPORT.

Case2: use xxx qw(OpenConnection $LoggedOn_user_id); #imports only the function OpenConnection and the scalar $LoggedOn_user_id. Once a list (the parens) after the "use" shows up, this has the effect of making @EXPORT the same as @EXPORT_OK. In other words, the symbols in @EXPORT are not imported by default and must be explicitly imported like the symbols in @EXPORT_OK. Any combination of symbols in @EXPORT or @EXPORT_OK can go in this list after the "use".

Case 3: (consequence of case 2), use xxx (); There is an empty list of stuff to import and nothing is imported - the automatic importing of the @EXPORT list is "Overridden".

When you import a symbol, you can use the "short" name, e.g. print $LoggedOn_user_id;. If we "used" the manageusers module, but did not import $LoggedOn_user_id, that variable can still be accessed with the fully qualified name, print $manageusers::LoggedOn_user_id; So if you use the fully qualified name, the variable or sub name does not need to be exported (provided that you have used the module to get it loaded). Only "our" variables can be exported or accessed from another module. A "my" lexical variable cannot be. "our" puts the symbol into the package's symbol table - that means among other things that the fully qualified name is going to work. Such an operation makes no sense for a lexical scope "my" variable.


#!/usr/bin/perl use warnings; use strict; package manageusers; BEGIN { use vars qw($VERSION @ISA @EXPORT); use DBI; # $ENV{DBI_TRACE}=1; # $ENV{PERL_DBI_DEBUG}=1; require Exporter; @ISA = qw(Exporter); # exported functions our @EXPORT_OK = qw( $attempts $adminaccess $LoggedOn_user_id Now CheckValidLoginChar CheckValidEmailChar print_md5_javascript); $VERSION = '0.0.1'; } our $LoggedOn_user_id=33; our $attempts = 99; 1;
#!/usr/bin/perl use strict; use warnings; use manageusers qw($LoggedOn_user_id); print "$LoggedOn_user_id\n"; #prints 33 print "$manageusers::attempts \n"; #prints 99 #Note that $attempts is NOT <strike>exported</strike> imported, but still #can be accessed by the fully qualified name!
I hope this helps. Its really early in the morning here, but I think I did this right. Run my code and then pare further questions down to just the basics and variables involved.

Corrected "use xx ();" comment. A bit twitchy with the CTL-V this morning. Also changed commend about $attempts in the mail program. Thanks shmem.

Replies are listed 'Best First'.
Re^4: global var
by haukex (Archbishop) on Apr 06, 2017 at 14:08 UTC
    use xxx (); #imports all of the symbols in @EXPORT use xxx qw(OpenConnection $LoggedOn_user_id); # imports # all of the symbols in @EXPORT AND subroutine OpenConnection # AND the scalar $LoggedOn_user_id from @EXPORT_OK

    Sorry, but those two are incorrect. As per use, use Foo (); is exactly equivalent to BEGIN { require Foo }, so nothing is exported at all. When you say use Foo qw/bar/;, Exporter exports only that, regardless of what's in @EXPORT.

    Update: Hm, my posting seems to have overlapped with an update to the node.

      Not impressed with EXPORT_OK. Have spent the last 4 hours adding functions to use xxx qw(....) and screwing lots of things up. Calls to cgi? action invoked functions calls that I then had to ad.

      Not worth it??

      My underlying problem still remains with one scalar value that will not import.


        Have spent the last 4 hours adding functions to use xxx qw(....) and screwing lots of things up.

        It would be better if you tried to understand what's going on. Doing the same thing over and over again and expecting a different output is tantamount to madness (paraphrasing Einstein).

        I would be glad if I could help you (call it helper syndrome if you want, or let it be as is.)

        Refactoring a shitty old codebase requires skills surpassing the ability to write the stuff, even if it is just restricting what Exporter exports, and fixing the subsequent importing mantras. As computing lore says:

        Debugging code is much harder than writing it in the first place. If you write your code as smart as you can, you are, by definition, too dumb to debug it.

        So, fixing that ol'crap requires. Use it as it is, and if you don't want to - or are told to not to: build the required skills. Read the docs. We won't spoonfeed them to you.

        Did you read the documentation of Exporter?

        I won't fix your stuff, even if I could, that ain't. I'm not being lured into teaching you basics. That has been your parents job, and if they didn't cope, it's yours now. Read the docs. Read the docs!

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

        Rather than trying in your application, make a SSCCE. I got one working in 10min, and I don't usually export scalars, so don't have much experience with it.

        package pm1187349; use warnings; use strict; use Exporter 'import'; our @EXPORT_OK = qw($someScalar someFunction); our $someScalar = "Scalar Text"; sub someFunction { print "I am some function\n"; }

        use warnings; use strict; use lib '.'; # don't import anything into the main:: namespace; must prefix everyth +ing with pm1187349:: use pm1187349; # use them pm1187349::someFunction(); print "someScalar = ${pm1187349::someScalar}\n";

        use warnings; use strict; use lib '.'; # import both a function and a scalar variable, so you don't need to p +refix with pm1187349:: use pm1187349 qw(someFunction $someScalar); # use them someFunction(); print "someScalar = ${someScalar}\n";
Re^4: global var
by tultalk (Monk) on Apr 06, 2017 at 14:31 UTC


    Thank you for this informative reply. I had not read anywhere this explanation:

    use xxx; #imports all of the symbols in @EXPORT use xxx (); #imports all of the symbols in @EXPORT use xxx qw(OpenConnection $LoggedOn_user_id); # imports # all of the symbols in @EXPORT AND subroutine OpenConnection # AND the scalar $LoggedOn_user_id from @EXPORT_OK [download]

    I was originally used the first example and calling all the subs with manageusers::sub and I guess that is why they worked and the scalars were imported also.

    I recently took a fellows advice and changed the export to our EXPORT_OK and am now having to put the called subs by name in use xxx qw(sub1 sub2... sub10) to get those calls working again.

    I guess its back to the drawing board on this.

    I did read that it is not good to use xxx; as it imports everything into that module, even subs/scalars that are only for other modules.

    Anyway thanks for the information and with that clarification I can probably resolve my issues.

    Best regards

      imports everything into that module, even subs/scalars

      The advice in What_Not_to_Export regarding scalars is this

      Do not export variable names. Just because Exporter lets you do that, it does not mean you should.
       @EXPORT_OK = qw($svar @avar %hvar); # DON'T!
      Exporting variables is not a good idea. They can change under the hood, provoking horrible effects at-a-distance that are too hard to track and to fix. Trust me: they are not worth it. To provide the capability to set/get class-wide settings, it is best instead to provide accessors as subroutines or class methods instead.

      Which is where I think this node started with the problem

      $userid = $manageusers::LoggedOn_user_id;

      and I think you were on the right path here in eliminating the global variables

      I also changed $LoggedOn_user_id to a function call &GetLoggedOn_user_id to deliver the number to the other module and it still does not work.

      I think you now know to make it work.

      Please see my 3rd attempt at explaining this "use" business.

      One problem with importing all of the @EXPORT stuff by default is that this can cause name conflicts. Also, if a program is large and uses a lot of modules, having an explicit import list can help with figuring out later what module something is in.

      Yes, if a variable is an "our" variable, the fully qualified name will work even if that particular symbol is not exported/imported. subs/functions go into the package symbol table in any event. One aspect of this is that there is no such thing as a truly private function in Perl. It is considered very bad form to call some function that is not part of the public interface, but Perl will not stop you from shooting yourself in the foot like that. If you know the function's name, you can call it.

      Oh, another point, in the @EXPORT list, you can ditch the leading & character (that's an old Perl 4 artifact). Put "someFunction" instead of "&someFunction".

Re^4: global var
by tultalk (Monk) on Apr 06, 2017 at 17:22 UTC

    Checked out the code you suggested and runs exactly as expected.

    Looked at my code, made sure exactly the same for the export and use and it failed exactly as before.

    Something is blocking the importing of the data through not exporting the $LoggedOn_user_id.

    I set the LoggedOn+user_id to a number to test ant did not import.

      I am glad that you ran my code and you see that it works.

      The file should have the "our" declaration of $LoggedON_user_id and this "our" declaration should not appear anywhere else.

      I am not sure what your remaining problem is, but I suspect that the solution will be simple once the problem is fully understood.

      Again, try to make a very, very simple example of the problem. Forget the web server for the moment. Get your script to work from the command line.

      Your "cgi" script doesn't even need to import $LoggedON_user_id as long as it does "use manageusers ();", (which imports nothing), you can still access $manageusers::LoggedON_user_id as long as has something like our $LoggedON_user_id = "default";

        I had tried that first but will try gain.

        In manageuser Removed EXPORT of LoggedON_user_id

        my $username1 = $session->param("user_id"); warn("username1 : '$username1'");

        Error Log manageusers

        Already logged on LoggedOn_user_id : '428' at /home/jalamior/www/httpsdocs/cgi-bin/lib/perl/ line 287. username1: '428' at /home/jalamior/www/httpsdocs/cgi-bin/lib/perl/ line 290.


        $LoggedOn_user_id = $username1; warn("Already logged on LoggedOn_user_id : '$LoggedOn_user_id'");

        And the error log

        Already logged on LoggedOn_user_id : '428' at /home/jalamior/www/httpsdocs/cgi-bin/lib/perl/ line 287

        So the desired value is present in the variable in manageusers

        In calling unit, changed import use manageusers; Commented out qw(LoggedOn_user_id);

        Line 66 in calling unit.

        $userid_1 = $manageusers::LoggedON_user_id;

        warn("userid : '$userid_1' ");

        Error Log line 66

        Sat Apr 8 06:54:25 2017 update_tables-development.cgi: Use of uninitialized value in concatenation (.) or string at update_tables-development.cgi line 66. userid : '' at update_tables-development.cgi line 66.

        Don't know where else to look

      In your original post you wrote 'I have global var in main unit:' and 'In another unit I have: use manageusers;'

      What do you mean by 'unit' ?. Do you have the same variable name declared in both the cgi script and the manageuser module something like this

      # cgi script use strict; our $LoggedOn_user_id = 0; # # # use manageusers qw($LoggedOn_user_id); print $LoggedOn_user_id;
      # package package manageusers; require Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw( $LoggedOn_user_id ); our $LoggedOn_user_id = 123; 1;

      The code prints 0 not 123


        our $LoggedOn_user_id = 0;

        Initializing variable. Later modified with data I want to share to other unit,

        Unit? Module? same difference, is it not?

        No on the var names being duplicated. Did multiple searches. Only one declaration with values loaded at different locations in program.

        This whole program is for a landlord association. Member logs on. Drill down to their status which is loaded into dataset displayed on form (using their unique id passed with $LoggedOn_user_id to the unit generating/displaying dataset. Display includes the number of tenants associated with this member. Next step is to drill down with click on that number to pull up another dataset of all tenants to display.

        When I manually set value in calling unit:

        #$userid_1 = manageusers::LoggedOn_user_id; #$userid_1 = $manageusers::LoggedOn_user_id; #$userid_1 = $LoggedOn_user_id; $userid_1 = 428;

        It of course works fine.

        Have another global

        $adminaccess = ($username1 eq "admin");

        To activate/inactivate menu items depending on login status using javascript in webpage. Logout succeeded form into iFrame deactivates menu through messaging.

        <script type="text/javascript"> var adminflag = $manageusers::adminaccess; </script>

        Passing variables not new.

        Export and calls look the same but I keep getting:

        Software error:

        "LoggedOn_user_id" is not exported by the manageusers module
        Can't continue after import errors at update_tables-development.cgi line 30
        BEGIN failed--compilation aborted at update_tables-development.cgi line 30.

        Do not understand. Not this way for others. Something unique about this.