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

I have been using the exporter module for some time now (as all good Camel-readers do) for exporting my package variables. I have been starting to turn strict on in my code modules, and this is causing me some greif. As we all know, strict wants all variables to be scoped either via 'my' or 'local' or exempted through 'use vars'.

I have found that by declaring a variable i want to export with a 'my' that it no longer exports successfully. This kind of makes sense but I am wondering how to now export variables and use 'strict' at the same time. Is use vars the only way, or is there something fundamental i do not understand about messing around with namespaces?

on a side note, i could find no information on how 'import' actually works or would be implemented.

  • Comment on use strict and exporting package variables

Replies are listed 'Best First'.
Re: use strict and exporting package variables
by chromatic (Archbishop) on May 01, 2001 at 04:26 UTC
    The vars pragma does more than "exempting" variables from the strict pragma. It creates an entry in the current package's symbol table for the named variable.

    That's important, because it's how you locate variables inside a package. (Variables declared with my or localized are bound to a particular lexical scope -- they don't live in the symbol table. I'm simplifying things here by ignoring what happens when you localize a variable in the symbol table.)

    The upshot of it is, import works by creating an alias in the current package's symbol table to point to a thingie in another package's symbol table.

    Since lexical variables don't live in a symbol table, that doesn't work.

    The important thing to remember is that namespaces use symbol tables, which are not the same thing as lexical scopes. I can get away with this jargon because you mention the Camel. :)

      You could, of course, put the lexical variables into the symbol table. Exporter doesn't do this, and I'm still even mostly sure that it's better that way.

      Some code (and it demonstrates how import() works, too):

      In test.pl:

      use MyTest; print "Once-lexical variable holds $lexvar\n";

      In MyTest.pm:

      package MyTest; my $lexvar = 7; # This function is called automatically whenever # anyone 'use's (or 'require's, I'm pretty sure) # our module. Note that this happens at COMPILE TIME. sub import { # symbol table manipulation usually requires # the use of symbolic references... no strict 'refs'; # Figure out where to export to. # Check `perldoc -f caller` for info on caller. my $pkg_to_export_to = (caller)[0]; # Make the scalar part of the entry in the symbol # table of the calling package for 'lexvar' into a hard # reference to our lexical variable. This is called # typeglob aliasing. *{$pkg_to_export_to . '::lexvar'} = \$lexvar; }

      Okay, maybe I'm just sick. ;-)

      bbfu
      Seasons don't fear The Reaper.
      Nor do the wind, the sun, and the rain.
      We can be like they are.

        FYI, Exporter can't do that since its code is in a different file and therefore has no access to the lexical variables in your module's file.

                - tye (but my friends call me "Tye")
Re: use strict and exporting package variables
by chipmunk (Parson) on May 01, 2001 at 08:07 UTC
    import works by making an alias between parts of the symbol table. For example:
    # export $MyPackage::var to $YourPackage::var *YourPackage::var = \$MyPackage::var;
    After this assignment, $YourPackage::var and $MyPackage::var now access the same scalar variable. The left hand side is a glob. I've used a reference to a scalar on the right hand side; this makes an alias only for the scalar. If the right-hand-side were also a glob, all the types (array, hash, etc.) for the name 'var' would have been aliased.

     

    This is how Exporter's import method works, except that it uses symbolic references to specify the names of the variables. For example:
    $callpackage = 'YourPackage; $pkg = 'MyPackage'; $sym = 'var'; ${"${callpkg}::$sym"} = \${"${pkg}::$sym"};
    This doesn't work for lexical variables, i.e. those declared with my, because they are not in the symbol table.

     

    However, it is possible to make an alias from the symbol table to a lexical variable:
    #!perl -l { my $var = 7; *Foo::var = \$var; print $Foo::var; foo(); print $var; } sub foo { # changes both $Foo::var and the lexical $var $Foo::var = 8; }
    So, you can write your own import method that exports lexical variables to the calling package, but you will have to either hard code the variable names or use eval, since the usual approach of symbolic references won't work.

     

    BTW, local does not declare a variable, as far as strict is concerned. In order to satisfy strict, variables without explicit package names must be declared with my or vars (or, in 5.6.0, our [offsite link]).
Re: use strict and exporting package variables
by satchboost (Scribe) on May 01, 2001 at 02:18 UTC
    One thing I do (which I feel is just sane design, let alone working with Exporter and use strict) is the following:

    package Foo; use Exporter; @ISA = qw(Exporter); @EXPORT_OK = qw(access_internal_var); use strict; my %Internal_Var_Here; sub access_internal_var { # Insert code here to access the hash }

    Now, in Perl5.6, you get the our keyword. That would modify the above as such:

    use strict; package Foo; use Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw(access_internal_var); . . .

    The reason I say that this is sane design is that this acts as encapsulation of global variables in a very local way.

Re: use strict and exporting package variables
by MeowChow (Vicar) on May 01, 2001 at 02:15 UTC
    my variables are lexically scoped, and can't be exported. Outside their scope, they can only be accessed or modified via a hard (non-symbolic) reference. You can learn alot about exporting, global variables, symbol tables, and aliases by actually reading through the Exporter.pm source code (it's a bit hairy at times, though you will learn a great deal). As of Perl 5.005, you can leave off the use vars and use the our declaration; though you may want to read this node before you sprinkle your code with our statements.
       MeowChow                                   
                   s aamecha.s a..a\u$&owag.print