Why does Perl warn about "useless constant 1" when using bigint? - perl

I was writing a module as part of my application when I noticed syntax check results in warning about useless use of a constant (1). Why is that?
The constant is the obligatory 1 at the end of the module which is normally ignored by warnings as perldoc perldiag says:
This warning will not be issued for numerical constants equal to 0 or 1 since they are often used in statements like
1 while sub_with_side_effects();
(There's probably an even better source for that. After all 1 at the end of files is totally desired and not to be warned about.)
But the warning is generated even for nearly empty modules if they use bigint.
package Foo;
use bigint;
1;
For this simple file syntax check produces the following warning:
$> perl -Wc Foo.pm
Useless use of a constant (1) in void context at Foo.pm line 5.
Foo.pm syntax OK
I could not find any reference to bigint and the warning message except Put long hex numbers in sqlite but this doesn't really address my issue, I think.
My Perl is v5.14.4 on Cygwin with bigint 0.36.

There are two issues at hand here.
Why does use bigint; 1; warn in void context?
Why is the constant being executed in void context in the first place?
$ perl -c -we'1 while sub_with_side_effects();'
-e syntax OK
$ perl -c -we'use bigint; 1 while sub_with_side_effects();'
Useless use of a constant (1) in void context at -e line 1.
-e syntax OK
Why does use bigint; 1; warn in void context?
use bigint; installs a callback that's called when a constant literal is encountered by the parser, and the value returned by the callback is used as the constant instead. As such, under use bigint;, 1 is no longer truly just a simple 0 or 1.
But you're not doing anything wrong, so this warning is spurious. You can work around it by using () or undef instead of 1.
undef while sub_with_side_effects();
Unless I needed to use it throughout my code base, I would favour the following:
while ( sub_with_side_effects() ) { }
$ cat Module.pm
package Module;
use bigint;
1;
$ perl -c -w Module.pm
Useless use of a constant (1) in void context at Module.pm line 3.
Module.pm syntax OK
Why is the constant being executed in void context?
When Perl executes a module, Perl expects the module to return a scalar value, so Perl should be executing the module in scalar context.
However, you told Perl to compile the script Module.pm. When Perl executes a script, Perl doesn't require any values to be returned, so Perl executes the script in void context.
Using a module as a script can cause spurious warnings and errors, and so can passing -W. Test a module using as follows:
perl -we'use Module'
Actually, you shouldn't even need -w since you should already have use warnings; in the module. All you really need is
perl -e'use Module'

-W instead of use warnings; in your module or checking modules with -c instead of perl -MFoo -e0 can show spurious errors. This is an example of the latter.
When you load a module normally, it isn't in void context, because it is checking that the result is true.
(Note that when I try it using 5.20.1, the -W also results in a spurious overload arg '..' is invalid at /usr/share/perl/5.20/Math/BigInt.pm line 155.)

Just leaving here a workaround to avoid the warning: Defining a constant with value 1 before using bigint:
package Foo;
use strict;
use warnings;
use constant PACKAGE_END => 1;
use bigint;
PACKAGE_END;

Related

Useless use of (/) in void context

When I try this code:
use strict;
use warnings;
print (44+66)/2;
It gave me:
Useless use of division (/) in void context at p.pl line 3.
But, after some tries, it worked by adding extra outer parentheses around the expression like:
use strict;
use warnings;
print ((44+66)/2);
And it did work!
Can anybody explain why?
Using Deparse will give you more information about how perl is parsing your code:
perl -MO=Deparse p.pl
Useless use of division (/) in void context at p.pl line 3.
use warnings;
use strict;
print(110) / 2;
p.pl syntax OK
Here you can see that the expression in the parens was evaluated as expected (66+44 = 110). But, then perl passes 110 as input to print, then tries to divide the output of print by 2.
Another helpful tool is diagnostics:
perl -Mdiagnostics p.pl
Useless use of division (/) in void context at p.pl line 3 (#1)
(W void) You did something without a side effect in a context that does
nothing with the return value, such as a statement that doesn't return a
value from a block, or the left side of a scalar comma operator. Very
often this points not to stupidity on your part, but a failure of Perl
to parse your program the way you thought it would.
It's great that you enabled warnings because it alerted you that there could be a problem with your code. When we run the code, we get 110 as output, whereas you expected 55.
The space between a function name and the opening parenthesis for the function call is optional. So when you write:
print (44+66)/2;
# ^ optional space!
Perl is assuming that you want to divide print(44+66) by 2 and then ignore the answer. So Perl warns you about performing an unnecessary division operation.
# workaround
print( (44+66)/2 );
# other workaround
print +(44+66)/2;

perl function definition fails with uninitialized value

My perl chops are a little stale so I'm probably missing something really obvious here, but I've added a small module to some older code CGI code to refactor common functions. Here is an excerpt of the module with the part that is giving me problems:
package Common;
use strict;
use warnings;
use base 'Exporter';
our #EXPORT_OK = (&fail_with_error);
sub fail_with_error {
my ($errmsg, $textcolor) = #_;
my $output = printf("<p><font color=\"%s\">ERROR: %s </font>/<p>", $textcolor, $errmsg);
print($output);
exit(1);
}
When I execute this module directly with perl Common.pm (or when I just import the function in test code, without even calling it) what I get is an uninitialized value error for $errmsg and $textcolor like this:
$ perl Common.pm
Use of uninitialized value $textcolor in printf at Common2.pm line 10.
Use of uninitialized value $errmsg in printf at Common2.pm line 10.
<p><font color="">ERROR: </font>/<p>1
It would seem that perl is giving the warning because it is executing the subroutine code literally, but the nature of a subroutine is that it is abstracted so different values can be passed in correct? It would stand to reason these shouldn't have to be populated to pass interpreter warnings, but nonetheless something is wrong.
I've searched around, but this error is very common because in most cases the variable really is uninitialized. I can't seem to find anything that applies to this type of case.
That's because you're accidentally populating #EXPORT_OK with a call to fail_with_error: &fail_with_error, instead of the function name. This calls fail_with_errors with the arguments populated from the current #_ which happens to be empty - so naturally both the variables are uninitialized (and also your function doesn't get exported). The correct assignment uses just the subroutine name:
our #EXPORT_OK = qw( fail_with_error );

How can I smoke out undefined subroutines?

I want to scan a code base to identify all instances of undefined subroutines that are not presently reachable.
As an example:
use strict;
use warnings;
my $flag = 0;
if ( $flag ) {
undefined_sub();
}
Observations
When $flag evaluates to true, the following warning is emitted:
Undefined subroutine &main::undefined_sub called at - line 6
I don't want to rely on warnings issued at run-time to identify undefined subroutines
The strict and warnings pragmas don't help here. use strict 'subs' has no effect.
Even the following code snippet is silent
$ perl -Mstrict -we 'exit 0; undefined_sub()'
Perhaps Subroutines::ProhibitCallsToUndeclaredSubs policy from Perl::Critic can help
This Policy checks that every unqualified subroutine call has a matching subroutine declaration in the current file, or that it explicitly appears in the import list for one of the included modules.
This "policy" is a part of Perl::Critic::StricterSubs, which needs to be installed. There are a few more policies there. This is considered a severity 4 violation, so you can do
perlcritic -4 script.pl
and parse the output for neither declared nor explicitly imported, or use
perlcritic -4 --single-policy ProhibitCallsToUndeclaredSubs script.pl
Some legitimate uses are still flagged, since it requires all subs to be imported explicitly.
This is a static analyzer, which I think should fit your purpose.
What you're asking for is in at least some sense impossible. Consider the following code snippet:
( rand()<0.5 ? *foo : *bar } = sub { say "Hello World!" };
foo();
There is a 50% chance that this will run OK, and a 50% chance that it will give an "Undefined subroutine" error. The decision is made at runtime, so it's not possible to tell before that what it will be. This is of course a contrived case to demonstrate a point, but runtime (or compile-time) generation of subroutines is not that uncommon in real code. For an example, look at how Moose adds functions that create methods. Static source code analysis will never be able to fully analyze such code.
B::Lint is probably about as good as something pre-runtime can get.
To find calls to subs that aren't defined at compile time, you can use B::Lint as follows:
a.pl:
use List::Util qw( min );
sub defined_sub { }
sub defined_later;
sub undefined_sub;
defined_sub();
defined_later();
undefined_sub();
undeclared_sub();
min();
max(); # XXX Didn't import
List::Util::max();
List::Util::mac(); # XXX Typo!
sub defined_later { }
Test:
$ perl -MO=Lint,undefined-subs a.pl
Undefined subroutine 'undefined_sub' called at a.pl line 9
Nonexistent subroutine 'undeclared_sub' called at a.pl line 10
Nonexistent subroutine 'max' called at a.pl line 12
Nonexistent subroutine 'List::Util::mac' called at a.pl line 14
a.pl syntax OK
Note that this is just for sub calls. Method calls (such as Class->method and method Class) aren't checked. But you are asking about sub calls.
Note that foo $x is a valid method call (using the indirect method call syntax) meaning $x->foo if foo isn't a valid function or sub, so B::Lint won't catch that. But it will catch foo($x).

using perl how can you figure out how to turn off a specific warning

I've got some legacy code that I'm dealing with. It's too much to clean up in one shot. It's using \1 inside of the s operator. I looked into perllexwarn and found I can shut it off with 'no warnings qw(syntax)', but I did this with trial and error. Is there an easier way to get right from the warning to the way to shut it off?
It's doing stuff like this:
use strict;
$_ = "abc";
s/abc/\1/;
no warnings qw(syntax);
s/abc/\1/;
the message it generates is :
\1 better written as $1
Execute your script as
perl -Mdiagnostics ./a.pl
or temporarily add use diagnostics; to your script. This will produce something like
\1 better written as $1 at ./a.pl line 4 (#1)
(W syntax) Outside of patterns, backreferences live on as variables.
The use of backslashes is grandfathered on the right-hand side of a
substitution, but stylistically it's better to use the variable form
because other Perl programmers will expect it, and it works better if
there are more than 9 backreferences.
Notice the (W syntax)? The letter is one of the following, and the word is the warning class for which you are looking.
(W) A warning (optional).
(D) A deprecation (enabled by default).
(S) A severe warning (enabled by default).
(F) A fatal error (trappable).
(P) An internal error you should never see (trappable).
(X) A very fatal error (nontrappable).
(A) An alien error message (not generated by Perl).
diagnostics gets its information from perldiag, which you could search manually instead of using use diagnostics;.
Other examples:
$ perl -Mdiagnostics -we'print undef'
Use of uninitialized value in print at -e line 1 (#1)
(W uninitialized) An undefined value was used as if it were already
[...]
$ perl -Mdiagnostics -we'no warnings qw( uninitialized ); print undef'
$ perl -Mdiagnostics -we'sub foo { } sub foo { }'
Subroutine foo redefined at -e line 1 (#1)
(W redefine) You redefined a subroutine. To suppress this warning, say
[...]
$ perl -Mdiagnostics -we'no warnings qw( redefine ); sub foo { } sub foo { }'
$
I'd make a global signal handler, set it in a BEGIN block so it's compiled in early, and skip only the warning you don't want, so you still get any potential unexpected and unrelated warnings (even within the same category, due to not having to disable the whole thing):
use warnings;
use strict;
BEGIN {
$SIG{__WARN__} = sub {
my $warn = shift;
return if $warn =~ /\\\d better written as/;
warn $warn;
};
}
my $x = 'abc';
$x =~ s/(abc)/\1/;
warn "a different warning\n";
Output:
a different warning
You can look the message up in perldoc perldiag. This will tell you the warning category it's in.

Make Perl warn me about missing unused functions [duplicate]

This question already has answers here:
How do I get perl -c to throw Undefined or Undeclared function errors?
(4 answers)
Closed 8 years ago.
perl -wle 'if (0) {no_such_func()}'
The above runs without errors, despite the -w, because no_such_func()
is never called.
How do I make Perl check all functions/modules I reference, even ones
I don't use?
In a more realistic case, some functions may only be called in special
cases, but I'd still like to make sure they exist.
EDIT: I installed perlcritic, but I think I'm still doing something wrong. I created this file:
#!/bin/perl -w
use strict;
if (0) {no_such_func();}
and perlcritic said it was fine ("source OK"). Surely static analysis could catch the non-existence of no_such_func()? The program also runs fine (and produces no output).
You can't do it because Perl doesn't see if functions exist until runtime. It can't. Consider a function that only gets evaled into existence:
eval 'sub foo { return $_[0]+1 }';
That line of code will create a subroutine at runtime.
Or consider that Perl can use symbolic references
my $func = 'func';
$func = "no_such_" . $func;
&$func;
In that case, it's calling your no_such_func function, but you can't tell via static analysis.
BTW, if you want to find functions that are never referenced, at least via static analysis, then you can use a tool like Perl::Critic. See http://perlcritic.com/ or install Perl::Critic from CPAN.
Hmm, this is difficult: When Perl parses a function call, it doesn't always know whether that function will exist. This is the case when a function is called before it's declared:
foo();
sub foo { say 42 }
Sometimes, the function may only be made available during runtime:
my $bar = sub { say 42 };
my $baz = sub { say "" };
*foo = rand > 0.5 ? $bar : $baz;
foo();
(I'd like to mention the “Only perl can parse Perl” meme at this point.)
I'm sure you could hack the perl internals to complain when the function can't be resolved before run time, but this is not really useful considering the use cases above.
You can force compile-time checks if you call all subs without parentheses. So the following will fail:
$ perl -e 'use strict; my $condvar; if ($condvar) {no_such_func}'
Bareword "no_such_func" not allowed while "strict subs" in use at -e line 1.
Execution of -e aborted due to compilation errors.
(However, it does not fail if you write if (0), it seems that perl's optimizer is removing the whole block without checking any further)
This has the consequence that you have to define all subroutines before using them. If you work like this, then sometimes "forward" declarations are necessary. But then it's possible that a forward declaration never gets a definition, which is another possible error case.