Why does strict complain about variables from a required other script? - perl

This is usex.pl:
#use strict;
require 'x.pl';
print $x;
Here is x.pl:
#use strict;
our $x = 99;
1;
It runs fine as shown. If I uncomment the line to use strict in usesx.pl, I get
Global symbol "$x" requires explicit package name
The use or not of strict in x.pl seems not to matter (unless I drop the 'our' keyword, but I'm not interested in that.)
I'm fairly new to Perl. Why does strict make $x not visible in the main script, and what is the normal solution to this?

Two reasons.
The error happens at compile-time, before require is ever executed. That's easy to fix using BEGIN.
our is lexically-scoped, and it's in a different lexical scope (file or block) than the print, so it's no longer in effect.
The whole approach is fundamentally bad. Here's one better way:
package MyConfig;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT = qw( $x );
our $x = 123;
1;
use strict;
use warnings;
use MyConfig;
print "$x\n";

Hehe, our is not easy to grok as it mixes the concepts of global and lexical scope. What it does is exempting a global variable from the strict 'vars' pragma and allowing unqualified access to it within its scope, which is the enclosing block, or the end of the current file, whatever comes first. Read the full (but brief) story in the manual, which is also accessible by saying perldoc -f our on the command line.
As for your script, you can verify the truthfulness of the words in the manual by modifying the variable accessor to use a package-qualified name:
use strict;
require 'x.pl';
print $main::x;

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.

Using a var to select a var in Perl

I thought you used to be able to do this in "strict" mode, but I may be remembering incorrectly. Is is possible for something like this to work...
use strict;
use warnings;
package SomePackage;
my $TargetPID="demo:5"; #using "our" also works, but not in strict mode
my $VarName="TargetPID";
print ${$VarName}; #works but not in strict or if the var is declared with "my"
exit;
The reason I'm interested is that I'm trying to select a variable based on a text flag in a text file and I'd like to read in the content of the text file into a hash, then substitute some identifier along the lines of "#TargetPID#" with the corresponding variable. Being also able to specify both a package and a variable (or constant) would be a nice tbonus.
I can't think of any advantage of doing it the way you are trying to over just using a hash:
use strict;
use warnings;
package SomePackage;
my %vars = ();
$vars{'TargetPID'}="demo:5";
my $VarName="TargetPID";
print $vars{$VarName};
exit;
If you really must use $TargetPID as a variable and not a member of a hash, you can use eval:
my $TargetPID = "demo:5";
my $VarName = '$TargetPID';
print eval $VarName;
Or, if for some reason you need the value of $VarName to be 'TargetPID' and not '$TargetPID', you can do print eval '$' . $VarName.
You can use the PadWalker module for this. From the documentation:
PadWalker is a module which allows you to inspect (and even change!)
lexical variables in any subroutine which called you. It will only
show those variables which are in scope at the point of the call.
In your case, you would need to use peek_my, which does what it says: it allows you to peek into variables declared by my in a given scope.
#!/usr/bin/perl
use warnings;
use strict;
package SomePackage;
use PadWalker qw/peek_my/;
my $TargetPID = "demo:5";
my $VarName = "TargetPID";
print ${peek_my(0)->{'$' . $VarName}}
The subroutine peek_my takes one argument, a level, which is the number of subroutine calls to go back on the stack. It then returns a hash map of all the lexical my variables that were in scope at the time of the given call. In your case, the variable you want is defined in the same scope as where it is needed, so you would pass in 0, to go back 0 subroutine calls. Then you pull out the data you need like any other hash ref.
Be careful though, from the documentation:
PadWalker is particularly useful for debugging (emphasis mine.) It's even used by
Perl's built-in debugger. (It can also be used for evil, of course.)
I wouldn't recommend using PadWalker directly in production code, but
it's your call. Some of the modules that use PadWalker internally are
certainly safe for and useful in production.

Should I use "use 5.12.0; use warnings;" in a perl module?

I am not sure if and what difference it makes if a start a perl module with
package MYPACKAGE;
use 5.12.0;
use warnings;
# functions are here
1;
or
use 5.12.0;
use warnings;
package MYPACKAGE;
# functions are here
1;
or if these use ... are not regarded at all because the use ... are inherited from the calling perl script.
The question probably boils down to: is it worthwile to specify those use ... in a module or is it sufficient if I have them specified in my perl script.
Pragmatic modules have lexical, not dynamic scope.
The version pragma activates certain features in the current scope, depending on the version. It doesn't activate these features globally. This is important for backwards-compability.
This means that a pragma can be activated outside of the module definition, but inside our scope:
# this is package main
use 5.012; # activates `say`
package Foo;
say "Hi"; # works, because lexical scope
This is different from normal imports that are imported into the current package (!= scope).
The warnings pragma activates warnings inside the current scope.
However, every file should contain the use strict, as lexical scope never stretches accross files. Pragmas are not transitive:
Foo.pm:
say "Hi";
1;
main.pl:
use 5.012;
require Foo;
fails.
Where exactly you put these pragmas is thus largely irrelevant. I'd recommend putting the pragmas before the package when you have multiple namespaces in the file, e.g.
use 5.012; use warnings;
package Foo;
...;
package Bar;
...;
1;
but to put the package first if it is the only one in the file.
package Foo;
use 5.012; use warnings;
...;
1;
The only important thing is that you do use them ;-)

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.

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;