Importing variable into Perl package - perl

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.

Related

Perl import into all my packages?

I tend to use Data::Dumper very often, and I end up having the following boilerplate at the top of every package in my .pl code.
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Deparse = 1;
$Data::Dumper::Purity = 1;
Is there a way to specify that "inside the current .pl file, I want these statements to automatically assumed."
eg I would have
package foo;
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Deparse = 1;
$Data::Dumper::Purity = 1;
my #localState = (1, 2, 3, 4, 5);
sub test {
print Dumper \#localState;
}
package main;
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Deparse = 1;
$Data::Dumper::Purity = 1;
foo->test;
this can quickly get way too much boilerplate repetition and harm maintainability.
Sadly I can't use a function with "eval" in it to call all this boilerplate since that boilerplate would be placed into the function, not global scope; Perl does not have Lisp macros that I know of to actually have non-function bound eval-like bahavior(I could be wrong, would be so cool if Perl had lisp macros).
Does anyone know if this behavior can be achieved without writing a parser to insert the statements in for me if it is the first package being declared inside file?
You can build your own toolbox module that turns on pragmas, loads modules and sets stuff, and just load that. The module Import::Into us great for that.
Here is a blog post that explains how to do it.
But note that the config for Data::Dumper that you are setting is actually not related to the package you're setting it in. Those are package variables in the Data::Dumper package, so they are valid all the time once set. You're essentially overwriting them with the same stuff again in your example.
In production code you should usually not put multiple packages in one file unless you have a good reason. But that doesn't change any of the advice above.

Perl: how to make variables from requiring script available in required script

example
out.pl:
(my|our|local|global|whatever???) var = "test";
require("inside.pm");
inside.pm:
print $var;
I don't want to use packages - it's overwhelming my needs :)
thanks!
You are always using a package, even if you don't use the package declaration. By default, you're working in package main.
All variables you declare with our are package variables and should be available package wide. Here's an example:
#! /usr/bin/env perl
# test2.pl
use strict;
use warnings;
our $foo = "bar";
1;
Since $foo is declared as a package variable, it will be available in other programs:
#! /usr/bin/env perl
use strict;
use warnings;
require "test2.pl";
our $foo;
print "The value of \$foo is $foo\n";
Now I've given you enough rope, I'm going to tell you not to hang yourself with it.
This is a REALLY, REALLY BAD IDEA. Notice that $foo gets a value from some sort of mysterious mechanism that's almost impossible to figure out?
Packages are too complex? Really? It's not that hard! Look at this example:
#! /usr/bin/env perl
# test2.pm
package test2;
use strict;
use warnings;
our $foo = "bar";
1;
Not much different than before except I added the package declaration and now call my program test2.pm instead of test2.pl.
Here's how I access it:
#! /usr/bin/env perl
use strict;
use warnings;
use test2;
print "The value of \$foo from package test2 is $test2::foo\n";
All I had to do was use the package name in the variable. This is a BAD IDEA, but it's way better than the REALLY, REALLY BAD IDEA shown above.
At least, you know where the value came from. It came from test2.pm. And, you could access the variable if you set it in a subroutine.
#! /usr/bin/env perl
# test2.pm
package test2;
use strict;
use warnings;
sub fooloader {
our $foo = "bar";
}
1;
Notice that $foo is set in the subroutine fooloader. And, here's my other program to access it:
#! /usr/bin/env perl
use strict;
use warnings;
use test2;
&test2::fooloader();
print "The value of \$foo from package test2 is $test2::foo\n";
Now, you could use the Exporter to export your subroutines (and even variables), but that's not something you see too much anymore. Mainly because it is a REALLY BAD IDEA. Not as bad as the original REALLY REALLY BAD IDEA, but worse than the BAD IDEA above:
#! /usr/bin/env perl
# test2.pm
package test2;
use base qw(Exporter);
our #EXPORT = qw(fooloader);
use strict;
use warnings;
sub fooloader {
our $foo = "bar";
}
1;
Now, I can use subroutine fooloader without the package name:
#! /usr/bin/env perl
use strict;
use warnings;
use test2;
fooloader();
print "The value of \$foo from package test2 is $test2::foo\n";
The problem, of course, is that you have no real idea where the subroutine fooloader is coming from. If you used #EXPORT_OK instead of #EXPORT, you could have then use use test2 qw(fooloader); and document where the fooloader function was coming from. It'll also help you to know not to create your own fooloader function in your own program and override the one you imported. Then, wonder why your program no longer works.
By the way, you could also export variables and not just functions. However, that becomes a REALLY, REALLY, REALLY BAD -- NO TERRIBLE IDEA because it violates every reason why you use packages in the first place. If you're going to do that, why bother with packages? Why not simple take a gun and shoot yourself in the foot?
The best and preferred way is to use object oriented Perl and do it in the THOROUGHLY CORRECT WAY. A way where you know exactly what's going on and why. And, makes it easy to figure out what your code is doing. A way that keeps errors at a minimum.
Behold the thoroughly object oriented Test2 class:
#! /usr/bin/env perl
# Test2.pm
package Test2;
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
return $self;
}
sub FooValue {
return "bar";
}
1;
And using that Test2 class:
#! /usr/bin/env perl
use strict;
use warnings;
use Test2;
my $tester = Test2->new;
print "The value of foo from package test2 is " . $tester->FooValue . "\n";
The reason this is the best way to do it is because even if you use packages, you could manipulate the value of $test2::foo and it will be changed in your entire program. Imagine if this was say $constants::pi and somewhere you changed it from 3.14159 to 3. From then on, using $constants::pi would give you the wrong value. If you use the object oriented method, you couldn't change the value of the method Constant->Pi. It will always be 3.14159.
So, what did we learn today?
We learned that it is very easy in Perl to do something that's a REALLY, REALLY BAD IDEA, but it doesn't take all that much work to use packages, so it merely becomes a BAD IDEA. And, if you start learning a bit of object oriented Perl, you can actually, without too much effort, do it all in the THOROUGHLY CORRECT WAY.
The choice is yours to make. Just remember the foot you're shooting will probably be your own.
It will work with our.
$ cat out.pl
our $var = "test";
require("inside.pm");
$ cat inside.pm
print "Testing...\n";
print "$var\n";
$ perl out.pl
Testing...
test
This works because our makes $var global, and inside.pm is being executed in the scope with $var defined. Not sure it is recommended technique, but it is an interesting question nevertheless!
EDIT: Need to clarify (okay patch) the answer based on a comment:
From the documentation on the Perl function our:
our associates a simple name with a package (read: global) variable in the current package, for use within the current lexical scope. In other words, our has the same scoping rules as my or state, but does not necessarily create a variable.
So using our, we get $var with the current package (here probably main) and we can use it in its scope. In effect it is then "global" to the code in the file you are requiring-in.
A true global is introduced without the our, because variables default to global. But I don't know anyone that would recommend them.

How can I share global values among different packages in Perl?

Is there a standard way to code a module to hold global application parameters to be included in every other package? For instance: use Config;?
A simple package that only contains our variables? What about readonly variables?
There's already a standard Config module, so choose a different name.
Say you have MyConfig.pm with the following contents:
package MyConfig;
our $Foo = "bar";
our %Baz = (quux => "potrzebie");
1;
Then other modules might use it as in
#! /usr/bin/perl
use warnings;
use strict;
use MyConfig;
print "Foo = $MyConfig::Foo\n";
print $MyConfig::Baz{quux}, "\n";
If you don't want to fully qualify the names, then use the standard Exporter module instead.
Add three lines to MyConfig.pm:
package MyConfig;
require Exporter;
our #ISA = qw/ Exporter /;
our #EXPORT = qw/ $Foo %Baz /;
our $Foo = "bar";
our %Baz = (quux => "potrzebie");
1;
Now the full package name is no longer necessary:
#! /usr/bin/perl
use warnings;
use strict;
use MyConfig;
print "Foo = $Foo\n";
print $Baz{quux}, "\n";
You could add a read-only scalar to MyConfig.pm with
our $READONLY;
*READONLY = \42;
This is documented in perlmod.
After adding it to #MyConfig::EXPORT, you might try
$READONLY = 3;
in a different module, but you'll get
Modification of a read-only value attempted at ./program line 12.
As an alternative, you could declare in MyConfig.pm constants using the constant module and then export those.
Don't use global variables for configuration and don't sotre configuration as code. I have an entire chapter in Mastering Perl about this.
Instead, make a configuration class that any other package can use to access the configuration data. It will be much easier in the long run to provide an interface to something you may want to change later than deal with the nuttiness you lock yourself into by scattering variables names you have to support for the rest of your life.
A config interface also gives you the benefit of composing new answers to configuration questions by combining the right bits of actual configuration data. You hide all of that behind a method and the higher levels don't have to see how it's implemented. For instance,
print "Hello!" unless $config->be_silent;
The be_silent answer can be triggered for multiple reasons the higher-level code doesn't need to know about. It could be from a user switch, that the program detected it is not interactive, and so on. It can also be flipped by options such as a debugging switch, which overrides all other preferences. No matter what you decide, that code line doesn't change because that statement only cares about the answer, not how you got the answer.

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()