Is there a way I can suppress uninitialized Perl variable warning for only few libraries out of all the libraries used in a Perl file?
I can't think of any reason this would be a good idea, surely use of an uninitialised variable is a bug which ever angle you look at it from?
However, you can turn the warnings off with:
no warnings 'uninitialized';
And on again with:
use warnings 'uninitialized';
You can disable the warnings for a single statement if you surround it with these two statements.
You probably used -w, which enables warnings throughout the interpreter (though it can be overridden using local $^W = 0; or no warnings;).
It's not a bad thing to use -w. All modules should tolerate this or defend against it (using no warnings;). But some aren't "warnings-safe".
It's more conventional to place use warnings; in each of your scripts and modules. This is method of enabling warnings is less intrusive since it won't affect other third-party modules used by your script and modules.
If you're able to modify the offending module(s), you can add no warnings 'uninitialized'; to the module itself, outside of any sub declarations, and it will disable that category of warnings for all code in the module, as demonstrated with these two bits of code:
In warntest:
#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;
use lib '.';
use UndefMod;
my $x;
say "Main before: $x";
UndefMod::test_mod;
say "Main after: $x";
In UndefMod.pm (in the same directory):
package UndefMod;
use strict;
use warnings;
use 5.010;
no warnings 'uninitialized';
sub test_mod {
my $x;
say "Module: $x";
}
1;
When run, this produces "Use of uninitialized value" warnings for both says in warntest, but no warning for the say in UndefMod, thus showing that either file's warnings setting has no effect on the other.
Of course, you may not be able to modify the module source, in which case you may be out of luck. Perl's scoping rules don't generally allow you to modify the warnings/no warnings state of a scope from outside that scope. (I say "may" and "generally" because there may be some black magic to hack around that, probably at least related to the magic behind PadWalker, but such things are beyond my ken.)
Related
I have the habit of starting each and every of my scripts with
use strict;
use warnings;
But some of the high-rep fellows here recommend
use warnings 'all';
If I understood them right, the latter is even better than the first. So I read through the docs and found
All warnings are enabled in a block by either of these:
use warnings;
use warnings 'all';
Even the Camel Book says nothing different:
use warnings; # same as importing "all"
So
is there a difference, or
is it just more future-proof (in case future versions of Perl issue warnings we aren't aware of right now and use warnings; won't catch), or
is it just another habit, like e.g. ps -ef vs. ps aux? Some people use this while others prefer the other.
Currently,
use warnings;
is equivalent to
use warnings 'all';
However, there has been talk on perl5porters of changing it to mean
use warnings 'default';
New "less-critical" warnings would be added to the "all" category but not shown by default. Since it seems this change is seriously being considered, it's safer to use warnings 'all'; explicitly.
Previous discussions on p5p:
RFC: Support for new warning categories outside of "all"
I've added support for new warning categories outside of "all" to blead
One is more explicit than the other, but as noted in the documentation, they have the same effect. It's probably better to use the 'all' import list to make it more clear that all warnings are in fact enabled. This is also helpful for those who may be new to Perl. When in doubt, explicit is usually better than implicit.
When using use strict perl will generate a runtime error on unsafe constructs. Now I am wondering if it is possible to have it only print a warning instead of causing a runtime error ? Or is use warnings (or -w) warning about the same issues ?
No, use strict can't be made to issue warnings rather than die. All it does is set a few bits in the magic $^H variable, which triggers various things in the guts of the Perl interpreter.
No, use warnings isn't warning about the same things as use strict kills you for. For instance, use warnings will warn you about variables used only once (which might be the result of typos).
I'm gonna take a stab at guessing the real motivation here. Feel free to tell me if I guessed wrong.
I suspect your trying to tackle a large, older code base and would like to enable strictures but you were hoping first to get a sense of where the errors will be (and how many there are) without breaking functionality. Unfortunately, since use strict functions by modifying the internal behavior of the perl parser and interpreter, there isn't a 'loose strict' or, by analogy to html, any kind of 'transitional' mode.
However, you can tease apart the functionality of use strict to start moving in the right direction. First, note that there are actually three separate parts:
use strict 'refs'; # no symbolic references
use strict 'vars'; # must declare variables
use strict 'subs'; # no barewords
and of those only 'refs' generates runtime errors. So you could easily add use strict qw(vars subs) to each of your files (scripts and modules) and test them with perl -c. If you encounter any error messages, then comment out the use strict, or at least whichever of the two checks failed, and add a comment as to the nature of the failure and move on. This way you can quickly (depending on the number of files) determine which files have compile-time errors and come back to address them later. (If you were more motivated than me at the moment, you could even automate this process). Unless you have code that does scary things inside of BEGIN blocks, this should be pretty safe to do.
The trickier part is checking for the runtime errors generated by use strict 'refs' and unfortunately, there really isn't an easy way to do this because the errors are triggered by symbolic references which can't be determined by any kind of static analysis so -c and/or Perl::Critic are both useless.
Hopefully that gets closer to addressing your real problem.
The warnings and strict pragmas are complementary, not overlapping. The strict pragma has both compile-time and run-time effects. You can't reduce the severity of strictures from errors to warnings, but you can disable them entirely. For example, if you're writing your own export routine you'll need to enable symbolic references in order to manipulate the symbol table.
{
no strict 'refs';
# symrefs okay within this block
}
Warnings can also be disabled lexically (assuming you did use warnings instead of the largely obsolete -w flag).
Strictures and warnings provide a safety net. That's why they're recommended to be used by default. If you disable them you should disable only what's necessary and limit the change to the smallest possible scope.
The preferred method:
use Carp;
sub foo {
croak "no args" unless #_;
}
eval foo();
if( $# ){
print "caught die: $#";
}
If you can't change your die's to croak's:
sub foo {
die "no args" unless #_;
}
{
my $prev_die = $SIG{__DIE__};
$SIG{__DIE__} = sub { print "caught die: $_[0]"; };
eval foo();
$SIG{__DIE__} = $prev_die;
}
The second method will print out the errors on STDERR.
See:
perldoc -f eval
perldoc perlvar and search for /\$\#/ and /__DIE__/
perldoc Carp
Warnings can be made fatal — see perllexwarn — but strict errors can't be made non-fatal.
Why do you want to do that? I suspect an XY problem.
I read that it is better to use warnings; instead of placing a -w at the end of the shebang.
What is the difference between the two?
The warnings pragma is a replacement for the command line flag -w, but the pragma is limited to the enclosing block, while the flag is global. See perllexwarn for more information and the list of built-in warning categories.
– warnings documentation
The advantage of use warnings is that it can be switched off, and only affects the immediate scope.
Consider for example a module that uses operations that would emit warnings:
package Idiotic;
sub stuff {
1 + undef;
}
Then we get a warning if we do
#!perl -w
use Idiotic; # oops, -w is global
Idiotic::stuff();
but don't get any warning with
#!perl
use warnings; # pragmas are scoped, yay!
use Idiotic;
Idiotic::stuff();
Yes, there is a difference, from warnings:
The warnings pragma is a replacement for the command line flag -w ,
but the pragma is limited to the enclosing block, while the flag is
global.
-w will enable warnings in included code (via use, etc.), and that may not be desirable.
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;
When using use strict perl will generate a runtime error on unsafe constructs. Now I am wondering if it is possible to have it only print a warning instead of causing a runtime error ? Or is use warnings (or -w) warning about the same issues ?
No, use strict can't be made to issue warnings rather than die. All it does is set a few bits in the magic $^H variable, which triggers various things in the guts of the Perl interpreter.
No, use warnings isn't warning about the same things as use strict kills you for. For instance, use warnings will warn you about variables used only once (which might be the result of typos).
I'm gonna take a stab at guessing the real motivation here. Feel free to tell me if I guessed wrong.
I suspect your trying to tackle a large, older code base and would like to enable strictures but you were hoping first to get a sense of where the errors will be (and how many there are) without breaking functionality. Unfortunately, since use strict functions by modifying the internal behavior of the perl parser and interpreter, there isn't a 'loose strict' or, by analogy to html, any kind of 'transitional' mode.
However, you can tease apart the functionality of use strict to start moving in the right direction. First, note that there are actually three separate parts:
use strict 'refs'; # no symbolic references
use strict 'vars'; # must declare variables
use strict 'subs'; # no barewords
and of those only 'refs' generates runtime errors. So you could easily add use strict qw(vars subs) to each of your files (scripts and modules) and test them with perl -c. If you encounter any error messages, then comment out the use strict, or at least whichever of the two checks failed, and add a comment as to the nature of the failure and move on. This way you can quickly (depending on the number of files) determine which files have compile-time errors and come back to address them later. (If you were more motivated than me at the moment, you could even automate this process). Unless you have code that does scary things inside of BEGIN blocks, this should be pretty safe to do.
The trickier part is checking for the runtime errors generated by use strict 'refs' and unfortunately, there really isn't an easy way to do this because the errors are triggered by symbolic references which can't be determined by any kind of static analysis so -c and/or Perl::Critic are both useless.
Hopefully that gets closer to addressing your real problem.
The warnings and strict pragmas are complementary, not overlapping. The strict pragma has both compile-time and run-time effects. You can't reduce the severity of strictures from errors to warnings, but you can disable them entirely. For example, if you're writing your own export routine you'll need to enable symbolic references in order to manipulate the symbol table.
{
no strict 'refs';
# symrefs okay within this block
}
Warnings can also be disabled lexically (assuming you did use warnings instead of the largely obsolete -w flag).
Strictures and warnings provide a safety net. That's why they're recommended to be used by default. If you disable them you should disable only what's necessary and limit the change to the smallest possible scope.
The preferred method:
use Carp;
sub foo {
croak "no args" unless #_;
}
eval foo();
if( $# ){
print "caught die: $#";
}
If you can't change your die's to croak's:
sub foo {
die "no args" unless #_;
}
{
my $prev_die = $SIG{__DIE__};
$SIG{__DIE__} = sub { print "caught die: $_[0]"; };
eval foo();
$SIG{__DIE__} = $prev_die;
}
The second method will print out the errors on STDERR.
See:
perldoc -f eval
perldoc perlvar and search for /\$\#/ and /__DIE__/
perldoc Carp
Warnings can be made fatal — see perllexwarn — but strict errors can't be made non-fatal.
Why do you want to do that? I suspect an XY problem.