Perl state variable requires explicit package name - perl

I am having problems getting state variables to work. I have extensive experience with "my" variables, but getting "state" variables to work hasn't been easy.
Here is a bare minimum example to reproduce the problem:
$ perl -e 'use strict; sub test {state $string = ""; print $string; }'
Global symbol "$string" requires explicit package name (did you forget to declare "my $string"?) at -e line 1.
Global symbol "$string" requires explicit package name (did you forget to declare "my $string"?) at -e line 1.
Execution of -e aborted due to compilation errors.
$ perl --version
This is perl 5, version 32, subversion 1 (v5.32.1) built for MSWin32-x64-multi-thread

According to the documentation for the state keyword:
state is available only if the "state" feature is enabled or if it is
prefixed with CORE::. The "state" feature is enabled automatically
with a use v5.10 (or higher) declaration in the current scope.
Here is one way to change your one-liner to avoid the error:
$ perl -e 'use strict; use feature "state"; sub test {state $string = ""; print $string; }'
The docs mention:
This feature is available starting with Perl 5.10.
Although you are using Perl version v5.32.1, which is later than 5.10, it is still necessary to explicitly enable the state feature using one of the methods shown in the documentation. This feature is currently not enabled by default for any version of Perl.

Related

Is there a way to get the Perl interpreter to list all the global variables in a pl file?

I have a huge system that I'm converting from a cgi to a daemon and I need to find all the variables that end up being global (as in not declared with my $...)
They are probably intended to be scoped locally, but in perl if you accidentally forget, it doesn't care, but now I do.
I gotta figure the perl interpreter can tell the difference, so is there a way to get it to tell me? I could go through all the code by hand, looking for declarations, but there thousands and thousands and thousands of lines of code in this system.
perldoc strict will show all variables not declared with my:
$ perl -Mstrict=vars -c -e '$x=5; my $y=7; $z=6;'
Global symbol "$x" requires explicit package name at -e line 1.
Global symbol "$z" requires explicit package name at -e line 1.
-e had compilation errors.
The same thing with a list of files:
$ perl -Mstrict=vars -c *.pl
Here is another way using perldoc B::Xref
$ perl -MO=Xref -e '$x=5; my $y=7; $z=6;'
... lots of verbose output
Subroutine (main)
Package (lexical)
$y i1
Package main
$x 1
$z 1
With the PadWalker Module you can see all variables in a specific scope. You can see variables declared with "my" and "our".
You should still use "use strict" but using "use strict" does not show you global variables that you declare as global.
For example this example still has a global variable and strict does not do anything
#!/usr/bin/env perl
use strict;
use warnings;
our $foo;
With PadWalker you can use something like this.
#!/usr/bin/env perl
use strict;
use warnings;
use DDP;
use PadWalker qw(peek_our);
our $var;
print p peek_our(0);
The output is
\ {
$var \ undef
}
Sure, you only should use PadWalker for Debugging.

installing perl in windows 7

I am pretty layman to Perl, never used it ...but now I want to use it.
Here is what I did:
http://www.activestate.com/activeperl/downloads
I installed universal version - 5.12.4.1205
To test my program is working, I used the following small program :
dnacon.plx
#i/Perl64/bin/perl -w
#Example 1-1 Concatenating DNA
$DNA1 = 'ATTTGGTAAAATGTATA'
$DNA2 = 'TTTTGGGTTTGAAAT'
print "Here are two DNA fragments: \n\n"
print $DNA1, "\n\n"
print $DNA2, "\n\n"
$DNA3 = "$DNA1$$DNA2"
print "$DNA3\n\n
When I try to execute it the following is command prompt with errors.
Sorry for too basic question...
EDTIS:
When I just type dnacon.plx, it is seems that it is working, but with error !!!
c:\myperllessions>dnacon.plx
Scalar found where operator expected at C:\myperllessions\dnacon.plx line 5, nea
r "$DNA2"
(Missing semicolon on previous line?)
syntax error at C:\myperllessions\dnacon.plx line 5, near "$DNA2 "
Execution of C:\myperllessions\dnacon.plx aborted due to compilation errors.
Am I good to go ??? What could be the error ...compilation errors ????
Edits:
I am using the following now : is this correct ?
#i/Perl64/bin -w
Edits:
I changed my script to following:
#i/Perl64/bin -w
#Example 1-1 Concatenating DNA
use strict;
use warnings;
$DNA1 = 'ATTTGGTAAAATGTATA';
$DNA2 = 'TTTTGGGTTTGAAAT';
print "Here are two DNA fragments: \n\n";
print $DNA1, "\n\n";
print $DNA2, "\n\n";
$DNA3 = "$DNA1$$DNA2";
print "$DNA3\n\n";
I got the following error:
c:\myperllessions>dnacon.plx
Global symbol "$DNA1" requires explicit package name at C:\myperllessions\dnacon
.plx line 5.
Global symbol "$DNA2" requires explicit package name at C:\myperllessions\dnacon
.plx line 6.
Global symbol "$DNA1" requires explicit package name at C:\myperllessions\dnacon
.plx line 9.
Global symbol "$DNA2" requires explicit package name at C:\myperllessions\dnacon
.plx line 10.
Global symbol "$DNA3" requires explicit package name at C:\myperllessions\dnacon
.plx line 12.
Global symbol "$DNA1" requires explicit package name at C:\myperllessions\dnacon
.plx line 12.
Global symbol "$DNA2" requires explicit package name at C:\myperllessions\dnacon
.plx line 12.
Global symbol "$DNA3" requires explicit package name at C:\myperllessions\dnacon
.plx line 13.
Execution of C:\myperllessions\dnacon.plx aborted due to compilation errors.
Is my problem now with programming knowledge or something to do with installation ?????
To get perl to be recognized, you must add C:\Perl64\bin to the PATH environment variable. Go to Control Panel > System > Advanced System Settings > Environment Variables. Edit the line containing PATH in the top box marked User variables for <user>, and add ;C:\Perl64\bin (note the semicolon) to the end. Be sure not to corrupt anything that's already there.
The problems you are left with in your latest edit - Global symbol requires explicit package name - are because you have added use strict (a very good thing to do) and you haven't declared your variables. Also the line #i/Perl64/bin -w won't do anything and may as well be removed. Write this instead
use strict;
use warnings;
my $DNA1 = 'ATTTGGTAAAATGTATA';
my $DNA2 = 'TTTTGGGTTTGAAAT';
print "Here are two DNA fragments: \n\n";
print $DNA1, "\n\n";
print $DNA2, "\n\n";
my $DNA3 = "$DNA1$$DNA2";
print "$DNA3\n\n";
Did you try out Strawberry perl? It takes care of setting up the environment vars for you.
An environment variable may not be set up yet.
Since I no longer use Windows, I cannot give you the exact step by step instructions, but I can tell you, that somewhere in System Properties, you'll find a place to edit the environment variables.
Edit the path variable and append 'C:\Perl64\bin\' to it.
P.S.:This is assuming that when you cd to the said path, you are able to run the perl program. If not, something is wrong with the installation. Try re-installing Perl.

How do I use a certain version (or higher) of a perl module in my perl script?

I'm using Term::ANSIColor in my Perl script to do colorization of terminal output, and I am using the colorstrip function, which was only added in Term::ANSIColor version 2.01, according to the changelog. So, is there a way to make my script automatically die with an appropriate error message if it doesn't find at least that version of Term::ANSIcolor?
Just:
use Term::ANSIColor 2.01;
See perldoc -f use:
use Module VERSION LIST
If the VERSION argument is present between Module and LIST, then the use will call the VERSION method in class Module with the given version as an argument. The default VERSION method, inherited from the UNIVERSAL class, croaks if the given version is larger than the value of the variable $Module::VERSION .
Most modules define the package variable $VERSION.
use Term::ANSIColor;
die "Sorry, this program needs Term::ANSIColor >= v2.01!\n"
unless $Term::ANSIColor::VERSION >= 2.01;
This is also a good way to specify a maximum version of a module.
use Module::Foo;
die "You need an *older* version of Module::Foo that ",
"still has the &barbaz method defined"
if $Module::Foo::VERSION >= 0.47;
Simply specify the version you want to use:
use Some::Module 2.13;
If the version is not at least 2.13, the operation will fail.
You can experiment with the version that is available on the command line:
perl -MSome::Module=9999 -e 'exit 0'
This will usually die with the wrong version number shown in the error message (unless the module you're trying to use happens to have a 5 digit or longer version number, or unless the module is like strict and doesn't like being loaded via the command line with a version number or like URI (see the comments for details)).
$ perl -MFile::Find=999 -e 'exit 0'
File::Find version 999 required--this is only version 1.07 at
/usr/perl5/5.8.4/lib/Exporter/Heavy.pm line 121.
BEGIN failed--compilation aborted.
$ perl -e 'use File::Find 999; exit 0'
File::Find version 999 required--this is only version 1.07 at -e line 1.
BEGIN failed--compilation aborted at -e line 1.
$
Run on a machine I don't normally use, hence the antiquated version of Perl.

Why doesn't Perl's $OSNAME work on Solaris?

I remember having used the variable $OSNAME in Linux.
Currently I'm working on a project on Solaris where I need to get the OS name and that variable is not working on Solaris.
Even a simple one line program does not work:
print "OS is $OSNAME\n";
it prints
OS is
Please help.
You need to use the English module.
$OSNAME is actually an alias for $^O, you can use $^O without using English module but to use $OSNAME you need to use the English module.
Also since use strict is missing you did not get any errors.
Always use use strict; in your program, it will help you catch these kinds of errors.
So try:
use English;
use strict;
print "Operating system is $OSNAME\n";
You can use print $^Oinstead.
Testing stuff from the command line, I get:
$ perl -E 'say $OSNAME'
$ perl -Mstrict -E 'say $OSNAME'
Global symbol "$OSNAME" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.
$ perl -Mstrict -MEnglish -E 'say $OSNAME'
linux
If $OSNAME ($^O) doesn't contain precisely the information you need, take a look at the values available to you from the Config module.

How can I use Perl 5.10 features inside the debugger?

I am unable to evaluate 'modern Perl' code inside the Perl debugger. It works OK when debugging the code in a file, but not from the prompt.
Minimal example:
# Activating 5-10 features with -E (it works)
$ perl -E 'say "x"'
x
# Calling the debugger with -E
# It works for infile code, but for prompt line code...
$ perl -dEbug Loading DB routines from perl5db.pl version 1.33
DB say "x"
String found where operator expected at (eval 16)[/local-perl/lib/5.12.1/perl5db.pl:638] line 2, near "say "x""
at (eval 16)[/local-perl/lib/5.12.1/perl5db.pl:638] line 2
eval '($#, $!, $^E, $,, $/, $\\, $^W) = #saved;package main; $^D = $^D | $DB::db_stop;say "x";
(Note: the same happens with "use feature ':5.10'".)
Am I missing something?
I found a reference to the issue here, but it's about a year old. However, the relevant portion of the Perl source hasn't changed since and can be seen here. Essentially, if you take a look at toke.c in the Perl source, you see the following:
if (PL_perldb) {
/* Generate a string of Perl code to load the debugger.
* If PERL5DB is set, it will return the contents of that,
* otherwise a compile-time require of perl5db.pl. */
const char * const pdb = PerlEnv_getenv("PERL5DB");
...
}
...
if (PL_minus_E)
sv_catpvs(PL_linestr,
"use feature ':5." STRINGIFY(PERL_VERSION) "';");
Basically, the debugger is loaded before the -E flag is processed, so the features aren't yet enabled when the debugger gets loaded. The gist of this is that you can't currently use -E with the -d command. If you want to use say, switch, or any other feature from the debug prompt, you have to do it like this:
DB<1> use feature 'say'; say "x"
x
The closest I've seen to a solution is:
copy perl5db.pl from your PERL5LIB to either somewhere in PERL5LIB or the current directory, with a different name, say myperl5db.pl
2. Edit myperl5db.pl to have use feature ':5.10'; (or just 'state', or just 'say') on the first line.
3. Set the environment variable PERL5DB to "BEGIN { require 'myperl5db.pl' }"
Which I found at PerlMonks.