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. :) | [reply] |
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. | [reply] [d/l] [select] |
| [reply] |
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]). | [reply] [d/l] [select] |
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. | [reply] [d/l] [select] |
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 | [reply] [d/l] [select] |