I am stuck while creating a perl Moose module.
I have a global pm module.
package XYZ;
require Exporter;
our @ISA = qw(Exporter); ## EDIT missed this line
our @EXPORT_OK = qw($VAR);
my $VAR1 = 1;
our $VAR = {'XYZ' => $VAR1};
1;
I want to get $VAR
in a Moose
module I'm creating
package THIS;
use Moose;
use YAML::XS;
sub get_all_blocks{
my ($self) = @_;
require $self->get_pkg(); # this returns the full path+name of the above package
# i cannot use use lib+use since the get_pkg starts complaining
our $VAR;
print YAML::XS::Dump($XYZ::VAR); # this works
print YAML::XS::Dump($VAR); # this does not work
# i cannot use the scope resolution since XYZ would keep changing.
}
1;
Can someone please help me with accessing variable?
EDIT: Missed one line in the package XYZ
code.
I cannot touch the package XYZ
since it is owned/used by someone else, I can just use it :(
Exporting variables may easily lead to trouble.
Why not
package XYZ;
use strict;
use warnings;
use Exporter qw(import);
our @EXPORT_OK = qw(get_var);
my $VAR = '...'; # no need for "our" now
sub get_var { return $VAR }
...
1;
and then
package THIS;
use warnings;
use strict;
use XYZ qw(get_var);
my $var = get_var();
...
1;
See Exporter.
As for what you tried to do, there are two direct problems
$VAR
from XYZ
is never imported into THIS
. If you need symbols from other packages you need to import them.† Those packages have to make them available first, so you need to add it to @EXPORT_OK
as well.
Like above but with $VAR
instead of get_var()
package XYZ;
...
use Exporter qw(import);
our @EXPORT_OK = qw($VAR);
our $VAR = '...'; # need be "our" for this
with
package THIS;
...
use XYZ qw($VAR);
print "$VAR\n";
Now $VAR
can be used directly, including being written to (unless declared constant); that can change its value under the feet of yet other code, which may never even know about any of it.
Another way is to use @EXPORT
and then those symbols are introduced into every program that says use Package;
. I strongly recommend to only use @EXPORT_OK
, when callers need to explicitly list what they want. That also nicely documents what is being used.
Even once you add that, there is still a variable with the same name in THIS
, which hides (masks, shadows) the $XYZ::VAR
. So remove our $VAR
in THIS
. This is an excellent example of one problem with globals. Once they're introduced we have to be careful about them always and everywhere.
But there are far greater problems with sharing variables across modules.
It makes code components entangled and the code gets harder and harder to work with. It runs contrary to principles of well defined scopes and modular design, it enables action at a distance, etc. Perl provides many good tools for structuring code and we rarely need globals and shared variables. It is telling that the Exporter
itself warns against that.
Note how now my $VAR
in XYZ
is not visible outside XYZ
; there is no way for any code outside XYZ
to know about it or to access it.‡ When it is our
then any code in the interpreter can write it simply as $XYZ::VAR
, and without even importing it; that's what we don't want.
Of course that there may be a need for or good use of exporting variables, what can occasionally be found in modules. That is an exception though, to be used sparingly and carefully.
† Unless they're declared as package globals under a lexical alias via our in their package, in which case they can be used anywhere as $TheirPackageName::varname
.
‡ This complete privacy is courtesy of my
.