3

Adding use strict to a perl program disables an important warning message. Is this a bug in perl?

This little program has a problem

#!/usr/bin/perl -w
my $rule;
sub applyRule() {
    eval $rule;
}
my $foo_bar;
$foo_bar = "mega-foo-bar-ness";
$rule = 's/#FOO_BAR/$foo_bar/g';
$_ = "Please replace #FOO_BAR with something.";
applyRule();
print STDERR "OUTPUT: $_\n";

and we get a helpful warning message when running that program:

$ ./test1.pl
Use of uninitialized value $foo_bar in substitution (s///) at (eval 1) line 1.
OUTPUT: Please replace  with something.

Now add use strict;

#!/usr/bin/perl -w
use strict;
my $rule;
sub applyRule() {
    eval $rule;
}
my $foo_bar;
$foo_bar = "mega-foo-bar-ness";
$rule = 's/#FOO_BAR/$foo_bar/g';
$_ = "Please replace #FOO_BAR with something.";
applyRule();
print STDERR "OUTPUT: $_\n";

The substitution just silently fails.

$ ./test1.pl
OUTPUT: Please replace #FOO_BAR with something.

When I have mysterious errors in perl should I always try removing use strict to see if I get some helpful warnings?

edit 1 stackoverflow is asking me to describe why this is not a duplicate of Why use strict and warnings?. This is a case where adding use strict results in fewer warnings, which makes debugging harder -- the opposite of what I expect use strict would do; the opposite of what is suggested in the answers to that question:

The pragmas catch many errors sooner than they would be caught otherwise, which makes it easier to find the root causes of the errors.

edit 2: For anyone else seeing this: another way is:

defined (eval $rule) or warn "eval error: $@\n";

because eval returns undefined if there is an error. The Programming Perl book states in the section about eval

If there is a syntax error or run-time error, eval returns the undefined value and puts the error message in $@. If there is no error, $@ is guaranteed to be set to the null string, so you can test it reliably afterward for errors.

Note however that with versions prior to Perl 5.14 there can be problems relying on '$@`.

Community
  • 1
  • 1
owler
  • 1,059
  • 8
  • 13
  • Possible duplicate of [Why use strict and warnings?](http://stackoverflow.com/questions/8023959/why-use-strict-and-warnings) – Thomas Dickey Mar 23 '16 at 22:45
  • short: add "use warnings 'all';" to improve the script. – Thomas Dickey Mar 23 '16 at 22:46
  • 1
    If you omit `use strict` the use of undeclared variables will not cause a compile time failure. So the `eval` will succeed, but a warning is printed. If you include `use strict`, `eval` will fail, and no warning is printed. – Håkon Hægland Mar 23 '16 at 23:16
  • Why are you using `eval`? It's completely unnecessary here. – ThisSuitIsBlackNot Mar 24 '16 at 03:31
  • This is the reduction to smallest example of a problem I found in a longer program. – owler Mar 24 '16 at 05:40
  • 2
    Do not use empty parentheses in sub declaration, it does not add anything that you need, and it does not work like in other languages. Parentheses in sub declarations are used to add prototypes, which are meant to help subroutines work like certain built-in functions. (E.g. `map { ... } @list` or `push @array, $value`.) – TLP Mar 24 '16 at 08:03

1 Answers1

21

Instead of a warning, it throws an exception. And you aren't testing to see if eval gave an exception.

Try:

eval "$rule; 1" or warn "exception thrown: $@\n";
ysth
  • 96,171
  • 6
  • 121
  • 214
  • Thanks, I learned that I need to explicitly check for errors when using `eval`. (I still think it's odd that `use strict` causes warnings to disappear but I get that it's because `eval` has a special way of reporting errors). – owler Mar 24 '16 at 05:39
  • 7
    the warning appears when stringizing an undefined value, but use strict makes it die while the eval is compiling `$rule`, well before it even starts the substitution search – ysth Mar 24 '16 at 06:32