In Perl, how can I access a scalar defined in another package? - perl

I seem to be stuck trying to access a scalar which is defined in another package, and have narrowed down an example to a simple test case where I can reproduce the issue.
What I wish to be able to do it access a reference to a list which is in defined within the package 'Example', using the our mechanism, however, Dumper is showing that the variable is always undefined within example.pl:
Example.pm looks like the following:
#!/usr/bin/perl -w
use strict;
use warnings;
use diagnostics;
package Example;
use Data::Dumper;
my $exported_array = [ 'one', 'two', 'three' ];
print Dumper $exported_array;
1;
And the code which uses this package looks like this:
#!/usr/bin/perl -w
use strict;
use warnings;
use diagnostics;
use Data::Dumper;
use lib '.';
use Example;
{ package Example;
use Data::Dumper;
our $exported_array;
print Dumper $exported_array;
}
exit 0;
Upon running this code, the first Dumper runs and things look normal, after this, the second Dumper, example.pl runs and the reference is then undefined:
$VAR1 = [
'one',
'two',
'three'
];
$VAR1 = undef;

A my declaration does not create a package level variable and does not enter anything onto the symbol table for any namespace.
To do what you look like you are trying to do, you will have to change the declaration in the first file to
our $exported_array = [ ... ];
You can then access it in another file as
$Example::exported_array

Even if $exported_array weren't lexically scoped in the Example package, Example's $exported_array and main's $exported_array are two different things. The easiest way to change the example you've given is to 1. change my to our in the Example declaration and explicitly qualify the variable name.
our $exported_array;
...
print Dumper $Example::exported_array;
Otherwise, you need to make Example an Exporter. (Or just write an Example::import routine--but I' not going to cover that.)
package Example;
our $exported_array = ...;
our #EXPORT_OK = qw<$exported_array>;
use parent qw<Exporter>;
And in the script:
use Example qw<$exported_array>;
However, as you can actually export arrays (not just refs), I would make that:
our #exported_array = (...);
our #EXPORT_OK = qw<#exported_array>;
...
use Example qw<#exported_array>;
...
print Dumper( \#exported_array );

When you use the my operator, you are lexically scoping the variable name to either the scope you're in or to the file.
If you want something to be visible as a qualified package array, you need to use our like you do in the driver code. I believe you also need to declare a few special exporter variables in the .pm file, but on the plus side you won't need to declare our $exported_array; in the driver file.

Using Exporter is fine for smaller projects, but if you have lots of code handling data that is internal to a module, things can get ... messy. Object-orientation is a lot friendlier for this type of thing.
Why not construct a method to fetch this data? In fact, why not just use Moose?
In your Example.pm, just load Moose - this gives you a constructor and destructor for free, as well as a subroutine to fetch values and turns on strict, etc by default. Array references have to be declared a little differently, due to how Class:MOP (The engine under the antlers of Moose) initializes attributes - you have to wrap it in a code reference (aka sub {}). You would also use Data::Dumper in the script which calls the package, instead of the package itself.
Example.pm
package Example;
use Moose;
has 'exported_array' => (is => 'rw', default => sub { [ 'one', 'two', 'three' ] });
1;
Then call this from a script:
example.pl
#!/usr/bin/env perl
use Modern::Perl '2013';
use lib '.';
use Example;
use Data::Dumper;
my $example = Example->new;
my $imported_array_ref = $example->exported_array;
my #imported_array = #{$imported_array_ref};
foreach my $element(#imported_array) { say $element; }
say Dumper(\#imported_array);
I made the dereferencing really explicit in the example.pl script above... it can be much more terse by dereferencing it directly into the array:
#!/usr/bin/env perl
use Modern::Perl '2013';
use lib '.';
use Example;
use Data::Dumper;
my $example = Example->new;
my #imported_array = #{$example->exported_array};
foreach my $element(#imported_array) { say $element; }
say Dumper(\#imported_array);
I think a lot more Perl programmers would embrace Moose if there were more simple examples that show how to get simple things done.
The Official Moose Manual is excellent, but it was really written for those who are already familiar with OOP.

Related

Importing variable into Perl package

I'm writing a basic program whose core logic is split across several project-specific modules for cleanliness (keeping subroutines organised by their purpose in the program's logic).
Suddenly had trouble exposing an option from the main package in one of the modules, and using the our statement appeared to have no effect.
For brevity, I'll copy+paste an isolated test case I wrote to examine this behaviour:
main.pl
#!/usr/bin/perl
use warnings;
use strict;
use File::Basename;
# The variable to be read by the module.
our $verbose = 1;
# Load Output.pm from directory
use lib dirname "$0";
use Output;
write_message "Hello, world\n";
Output.pm
package Output;
use warnings;
use strict;
use parent "Exporter";
our #EXPORT = qw(write_message);
# Should be imported?
our $verbose;
sub write_message {
print $_[0] unless !$verbose;
}
1;
Expected result: "Hello, world"
Actual result: Dead silence
It's quite possible that what I'm trying to achieve isn't even possible in Perl, as this isn't the intended use of modules (and heck, I understand why that'd be the case).
I'm still quite new to Perl and there are some things I'm struggling to wrap my head around. I've seen people recommend using the our declarator to expose a variable across packages, but I can't understand why this isn't working.
PS: If anybody knows a better approach to splitting an app's program-specific logic between modules, I'd appreciate some pointers too. :) But first and foremost, I'd prefer to learn why our-ing a variable isn't working.
An our statement just creates a package variable (whereas my creates a lexical variable). It has nothing to do with exporting
The best option is probably to declare the variable in the Output package and access it as $Output::verbose elsewhere. Like this
main.pl
#!/usr/bin/perl
use strict;
use warnings;
use File::Basename;
use lib dirname $0;
use Output;
$Output::verbose = 1;
write_message "Hello, world\n";
Output.pm
package Output;
use strict;
use warnings;
use Exporter 5.57 'import';
our #EXPORT = qw/ write_message /;
our $verbose;
sub write_message {
print $_[0] if $verbose;
}
1;
Note that I have also removed the incorrect quotes from around $0, and ever since version 5.57 of Exporter it has been possible (and preferable) to import it's import subroutine instead of subclassing it
our declares a package variable in the current package. The one in main.pl refers to $main::verbose; the one in Output.pm refers to $Output::verbose.
You can use the full name $main::verbose to access the variable from anywhere, but you can't really "export" it because exporting refers to making symbols accessible to users of your module. You're trying to do the opposite.

imported perl variable imports with no value

SOLVED: As it turns out, my problem was rooted in the fact that I was not putting a $ in front of DEBUGVAR in the #EXPORT_OK assignment and the "use config_global qw(config DEBUGVAR);" line. Since it raises no error, I had no way to know this was the issue. So, the fix is to place the proper syntax in front of your variables at these points.
So I am trying to get the hang of writing and importing perl modules. I don't know why it was made so difficult to do this, but I am having a great deal of trouble with this seeimingly trivial task. Here is the contents of my module:
package global_config;
use strict;
require Exporter;
our #ISA = qw(Exporter);
our #EXPORT_OK = qw(DEBUGVAR);
our ($DEBUGVAR);
our $DEBUGVAR = "Hello, World!";
return 1;
Here are the contents of my perl script that imports the module:
use strict;
use config_global qw(config, DEBUGVAR);
our %config;
our $DEBUGVAR;
print "variable imported with value: ".$DEBUGVAR;
The output is "variable imported with value:", and nothing else. My variable appears to be losing it's value. What am I doing wrong?
EDIT: After fiddling around a bit, and turning warnings on, I have isolated the issue to being that $DEBUGVAR is never actually imported. When I use it via $config_global:DEBUGVAR, it works as expected. The issue now is that it is not importing into the namespace. What gives?
I see several issues:
You should not use a comma in the qw() syntax. The qw takes each whitespace separated phrase and puts it in an array element.
These two are the same:
my #bar = qw(foo bar barfu); #No commas!
my #bar = ("foo", "bar", "barfu"); #Commas Required
If you're exporting a variable, you need to put the sigil in front of it.
You have:
our #EXPORT_OK = qw(DEBUGVAR);
It should be:
our #EXPORT_OK = qw($DEBUGVAR);
You should use the newer Exporter syntax:
Here's the newer Exporter Syntax:
package global_config;
use strict;
use warnings;
use Exporter 'import'; #Not "require". No need for "#ISA"
our #EXPORT_OK = qw(DEBUGVAR);
our $DEBUGVAR = "Hello, World";
1; #Makes no real difference, but you shouldn't say "return 1". Just standard.
Finally, what are you doing exporting variables? That's just a bad practice.
Exporting anything is now questioned -- even functions. It pollutes the user's namespace. (At least you're using #EXPORT_OKAY). Take a look at File::Spec. It uses fully qualified package names for its subroutines by default.
The variable in question is accessible via the full package name $global_config::DEBUGVAR, so there's no real need to export it.
What if everybody did it? Yes, you last heard of this excuse in kindergarten, but it applies here. Imagine if several modules exported $DEBUGVAR.
There are several ways around your quandary, but the best is to use object oriented Perl to help set this variable, and even allow users to change it.
package MyPackage;
use strict;
use warnings;
use feature qw(say);
sub new {
my $class = shift;
my $debug = shift; #Optional Debug Value
my $self = {};
bless $self, $class;
if (not defined $debug) {
$debug = "Hello, world!";
$self->Debug($debug);
return $self;
}
sub Debug {
my $self = shift;
my $debug = shift;
if (defined $debug) {
$self->{DEBUG} = $debug;
}
return $debug;
}
1;
To use this module, I simply create a new object, and Debug will be set for me:
use strict;
use warnings;
use MyPackage #No exporting needed
#Create an object w/ Debug value;
my $obj = MyPackage->new; #Debug is the default.
say $obj->Debug; #Prints "Hello, world!"
# Change the value of Debug
$obj->Debug("Foo!");
say $obj->Debug; #Now prints "Foo!"
#Create a new object with a different default debug
$obj2 = MyPackage->new("Bar!");
say $obj2->Debug; #Print "Bar!";
This solves several issues:
It allows multiple values of debug because each object now has its own values
There is no worry about namespace pollution or accessing package variables. Again, all you need is contained in the object itself.
It's easier to debug issues since the complexity is hidden inside the objects themselves.
It's the new preferred method, so you might as well get use to the syntax and be able to read object oriented Perl code. You'll be seeing it more and more.
While exporting variables from a package isn't necessarily a recommended practice, to do so, you need to use the actual name of the variable you are exporting. In this case it is $DEBUGVAR and not DEBUGVAR which would be the name of a subroutine.
In the script using the config module, you do not need to declare the $DEBUGVAR variable as our, since imported variables are exempt from strict vars.
You have gotten the name mixed up, it looks like:
use config_global ...
package global_config;
Though one would think that would issue warnings. Unless you are not using warnings...?
ETA:
our #EXPORT_OK = qw($DEBUGVAR);
^
Also, you have two declarations on that variable. You really need to use warnings when debugging, otherwise, you'll never get anywhere.
Are you sure you want a comma here:
use config_global qw(config, DEBUGVAR);
Also, you aren't exporting config, so it might work better as:
use config_global qw(DEBUGVAR);
I'd also remove the last our $DEBUGVAR; since it might set it to undef (or at least put it before the "use" line) -- I am not sure about this though.

How should I serialize code references in Perl?

I wish to nstore a Perl hash which also contains a code reference. Following this perldoc I wrote something like this:
use strict;
use warnings;
local $Storable::Deparse = 1;
my %hash = (... CODE => ...);
nstore (\%hash, $file);
I get a warning saying Name "Storable::Deparse" used only once: possible typo at test4.pl line 15.. I guess I could specifically suppress this warning, but it makes me wonder if I'm doing anything wrong.
Note this question relates to this one. Different titles to distinguish between the two will be most welcomed.
You have neglected to load the Storable module, before setting one of its config values.
use strict;
use warnings;
use Storable qw(nstore);
local $Storable::Deparse = 1;
my %hash = (... CODE => ...);
nstore (\%hash, $file);
Code references cannot be simply serialized. File handles, database connections, and anything that has external resources cannot be simply serialized.
When serializing such items, you must describe them in such a way that they can be recreated. For instance, you might serialize a file handle as a path and an offset or a code reference as the name of function the reference was pointing to.
You can find the name of the subroutine a code reference points to with Sub::Identify:
#!/usr/bin/perl
use strict;
use warnings;
use Sub::Identify qw/sub_fullname/;
sub foo {}
my $r = \&foo;
print sub_fullname($r), "\n";
Of course, this means you cannot serialize anonymous references and the serialized data can only reliably be used by programs that implement the named functions in the same way.
If you find yourself needing to do this, you are probably better off using a class instead of a simple code reference.
You also need to set
$Storable::Eval = 1;
thus:
#! perl
use strict;
use warnings;
use Storable qw /nstore retrieve/;
local $Storable::Deparse = 1;
local $Storable::Eval = 1;
my %hash = ( CODE => sub {print "ahoj\n";});
nstore (\%hash, 'test');
my $retrieved = retrieve ( 'test');
$retrieved->{CODE}();

Why can't my Perl script see the our() variables I defined in another file?

I have a question relating to Perl and scoping. I have a common file with lots of various variables. I require the common file in my main script, but I cannot access the variables; they seem to be outside of its scope. I assumed that an our declaration would overcome that problem, but it doesn't seem to work.
Script 1: common.pl
#!/usr/bin/perl
our $var1 = "something";
our $var2 = "somethingelse";
Script 2: ftp.pl
#!/usr/bin/perl
use strict;
use warnings;
require('common.pl');
print $var1;
I get the error: Global symbol "$var1" requires explicit package name
There's no require statement in your second example, but it wouldn't work anyway. What our does is declare a lexically-scoped package variable. Since you have no package statement, it uses the default package main. So your first script sets up the variable $main::var1, but this will only be available within that file's scope.
A better way to provide common variables for other scripts is to use Exporter. You can define package symbols in one place and Exporter will take care of copying them to the requesting script or class's namespace when needed.
I would put the config in a module instead.
File: MyConfig.pm
package MyConfig;
require Exporter;
use strict;
our #ISA = qw(Exporter);
our #EXPORT = qw( getconfig );
my %confighash = (
thisone => 'one',
thatone => 2,
somthingelse => 'froboz',
);
sub getconfig {
return %confighash;
}
1;
Example usage:
#!/usr/bin/perl
use strict;
use warnings;
use MyConfig;
my %config = getconfig();
print $config{ somthingelse };
This should print froboz
It looks like you need a proper configuration file there. I'd go for a non-code configuration file that you can read when you need to setup things. There are modules on CPAN to handle just about any configuration format you can imagine.
If you want to do it the way you have it, get rid of our and declare them with use vars. Don't let the PBP police scare you off that. :) You only really need our to limit a scope of a package variable, and that's exactly the opposite of what you are trying to do.
our() does something a little different than you think. Its sole purpose is to work with strict in requiring you to declare package variables that you are going to use (unless they are fully-qualified or imported). Like strict, its effect is lexically-scoped. To use it to allow accessing a global $main:var1 from multiple files (which are separate scopes) as just $var1, you need to say our $var1 in each file.
Alternatively, you would change your required file to be a module with its own package that exports the variables to any package that uses it.
Try this. I am new at Perl but this is how I got it to work on a script I made
#!/usr/bin/perl
$var1 = "something";
$var2 = "somethingelse";
Script 2: ftp.pl
#!/usr/bin/perl
use strict;
use warnings;
our $var1;
our $var2;
require('common.pl');
print $var1;

Is there a way to "use" a single file that in turn uses multiple others in Perl?

I'd like to create several modules that will be used in nearly all scripts and modules in my project. These could be used in each of my scripts like so:
#!/usr/bin/perl
use Foo::Bar;
use Foo::Baz;
use Foo::Qux;
use Foo::Quux;
# Potentially many more.
Is it possible to move all these use statements to a new module Foo::Corge and then only have to use Foo::Corge in each of my scripts and modules?
Yes, it is possible, but no, you shouldn't do it.
I just spent two weeks to get rid of a module that did nothing but use other modules. I guess this module started out simple and innocent. But over the years it grew into a huge beast with lots and lots of use-statements, most of which weren't needed for any given run of our webapp. Finally, it took some 20 seconds just to 'use' that module. And it supported lazy copy-and-paste module creation.
So again: you may regret that step in a couple of months or years. And what do you get on the plus side? You saved typing a couple of lines in a couple of modules. Big deal.
Something like this should work:
http://mail.pm.org/pipermail/chicago-talk/2008-March/004829.html
Basically, create your package with lots of modules:
package Lots::Of::Modules;
use strict; # strictly optional, really
# These are the modules we want everywhere we say "use Lots::Of::Modules".
# Any exports are re-imported to the module that says "use Lots::Of::Modules"
use Carp qw/confess cluck/;
use Path::Class qw/file dir/;
...
sub import {
my $caller = caller;
my $class = shift;
no strict;
*{ $caller. '::'. $_ } = \*{ $class. '::'. $_ }
for grep { !/(?:BEGIN|import)/ } keys %{ $class. '::' };
}
Then use Lots::Of::Modules elsewhere;
use Lots::Of::Modules;
confess 'OH NOES';
Yes.
In Foo/Corge.pm
use Foo::Bar;
use Foo::Baz;
use Foo::Qux;
use Foo::Quux;
1; # Be successful
All that is left is to get the directory containing sub-directory Foo added to your library path (#INC). Alternatively, create Foo.pm and have it use the other modules. They would be in a Foo sub -directory beside Foo.pm.
If you think about it, all the complex Perl modules that use other modules do this all the time. They are not necessarily in the same top-level package (Foo in this example), but they are used just as necessarily.
While you could use Carp, and Path::Class and confess, and so on (as jrockway suggests), that seems like overkill from where I'm sitting.
[EDIT: My earlier solution involving use Lots::Of::Modules; had a subtle bug -- see bottom. The fix makes things a bit uglier, but still workable.]
[EDIT #2: Added BEGIN { ... } around the code to ensure that any functions defined are available at compile time. Thanks to jrockway for pointing this out.]
The following code will do exactly what jrockway's code does, only simpler and clearer:
In Lots/Of/Modules.inc:
use Carp qw/confess cluck/;
use Path::Class qw/file dir/;
0; # Flag an error if called with "use" or "require" instead of "do"
To import those 4 functions:
BEGIN { defined( do 'Lots/Of/Modules.inc' ) or die; }
Because we don't have a package Lots::Of::Modules; statement at the start of this file, the use statements will export into the caller's package.
We must use do instead of use or require, since the latter will only load the file once (causing failure if use Lots::Of::Modules; is called more than once, e.g. in separate modules used by the main program). The more primitive do does not throw an exception if it fails to find the file named by its argument in #INC, hence the need for checking the result with defined.
Another option would be for Foo::Corge to just re-export any items of interest normally:
package Foo::Corge;
use base 'Exporter';
BEGIN {
our #EXPORT_OK = qw( bar baz qux quux );
use Foo::Bar qw( bar );
use Foo::Baz qw( baz );
use Foo::Qux qw( qux );
use Foo::Quux qw( quux );
}
1;
(The 'use' statements can probably go outside the BEGIN, but that's where they were in the code I checked to verify that this worked the way I thought it did. That code actually evals the uses, so it has a reason for them to be inside BEGIN which likely doesn't apply in your case.)
using #EXPORT instead #EXPORT_OK , is more simple
Library is :
package mycommon;
use strict;
use warnings;
use base 'Exporter';
our #EXPORT = qw(test);
sub test {
print "this is a test";
}
1;
use it:
#!/usr/bin/perl
use strict;
use warnings;
use mycommon;
common::test()