Perl: print compilation warnings for do() - perl

I am using do() to execute a perl script. I wanted to make sure it was doing the right error checking, but I noticed that warnings don't get printed when I use do(). I left the following warning on purpose in my script. I see it when I run it on the command line
Useless use of numeric eq (==) in void context at utils/queryEvent/query_event.pl line 47.
When I use do(), this message is suppressed. I saw in perlvar that $# doesn't contain warnings, so I tried to add this before my call to do(), but I still don't see anything.
local $SIG{__WARN__} = sub {
print "Warning #_\n";
};
do(...);
Is there a way I can still print the compilation/parsing warnings?
I'm using Perl v.5.22.1 on Windows 10.
Added edit:
Both the script calling do() and the script being run through do() have use strict; and use warnings;. It is only the parsing warning that isn't showing up. If I call warn in the do script, then I see that (I'm assuming stderr).
Edit:
Adding example script.
A minimal reproducible version is the following
use strict;
use warnings;
sub test
{
return 1;
}
main:
{
(test() == 1);
}
Calling script
use strict;
use warnings;
main:
{
do('test.pl');
}

You are mistaken. do doesn't affect warnings in the least.
There is no warning because there is nothing that should cause a warning. (test() == 1) isn't being evaluated in void context. Instead, its result is returned by do.
But while warnings AREN'T being silenced, exceptions ARE being silenced. Fixing this will fix the other.
Add a trailing 1 to the file loaded by do, and change the do as follows:
do('test.pl')
or die( "Can't execute `./test.pl`: ".( $# // $! ) );
The trailing 1 is used to signal the "caller" whether an error occurred or not. This has the side effect of cause (test() == 1) to be evaluated in void context as expected.

The -w or -W command-line switches will enable warnings throughout your program, including code included through a do statement.

Related

Perl unexpected behavior: croak vs. try catch

I had seen some exceptions that pointed to (end of) the catch block itself (see the example below).
As my opinion, this is an unexpected behavior, since it alters the location of original exception and make difficult to debug (it should say die at line 13.)
It shows the (correct) line 13, if I use die/confess or using eval instead try-catch.
Not knowing how my code will be called within the stack, I started to avoid using croak now. What do you think? Did I get right, or there is a way to improve this?
Best regards, Steve
use Carp;
use Try::Tiny;
try {
foo();
}
catch {
# do something before die
die $_;
}; # this is line 10
sub foo {
croak 'die'; # this is line 13
}
Output:
die at line 10.
This is the intended behavior from Carp
[...] use carp() or croak() which report the error as being from where your module was called. [...] There is no guarantee that that is where the error was, but it is a good educated guess.
So the error is reported at where the module's sub is called, which is what the user wants
use warnings;
use strict;
use feature 'say';
use Try::Tiny;
package Throw {
use warnings;
use Carp qw(croak confess);
#sub bam { die "die in module" }; # l.11
sub bam { croak "croak in module" };
1;
};
try {
Throw::bam(); # l.17
}
catch {
say "caught one: $_";
die "die in catch: $_";
};
say "done";
Prints
caught one: croak in module at exceptions.pl line 17.
die in catch: croak in module at exceptions.pl line 17.
If the sub throws using die then this is reported at line 11, what is the normal behavior of die, and what you seem to expect.
If any of this is unclear or suboptimal then better use confess and nicely get a full stacktrace. Also, if you wish more exception-based-like code behavior, can put together an exception/error class and throw its object,† designed and populated as desired.
If you want to confess an object note that at this time Carp has limits with that
The Carp routines don't handle exception objects currently. If called with a first argument that is a reference, they simply call die() or warn(), as appropriate.
One way then would be to confess a stringification of the object,‡ getting at least both a full stack backtrace and whatever is in the object.
I get the same behavior with eval, by replacing try-catch and $_ above
eval {
Throw::bam();
};
if ($#) {
say "caught one: $#";
die "die in catch: $#";
};
Prints exactly the same as above
While the above is clear and behaves as expected, a weird thing is indeed seen in the question's example: the error is reported from the whole try-catch statement, ie. at its closing brace, where line 10 is. (The try sub is prototyped and the whole try-catch is a syntax aid equivalent to a call to try that takes an anonymous sub, and then perhaps more. See ikegami's comment, and docs. Also see this post for more about its syntax.)
This is strange since the call to the croaking sub is foo() inside the try statement and this line should be reported, what can be confirmed by running the script with -MCarp::Always. But in the code in this answer the line of the call to Throw::bam is indeed reported -- why this difference?
The clear purpose of croak is to be used in the libraries, so that the user can see at which point in their (user's) code they called the library in a way that triggered an error. (While die would point to the place where error is detected, so in the library, most likely useless to the user. But read die and Carp docs for related complexities.)
What isn't obvious is that when croak is emitted in the same namespace (main::foo()) from try-catch in its own namespace (Try::Tiny) things get confused, and the end of its statement is reported. This can be checked by adding a foo() to my code above and calling it (instead of a sub from a module), and we get the question's behavior reproduced.
This doesn't happen if main::foo() with croak inside is called from a (complex) statement right in main::, so it seems to be due to the try-catch mix up of namespaces. (On the other hand, try-catch sugar adds an anonymous sub to the callstack, and this sure can mix things up as well.)
In practical terms, I'd say: always use croak out of modules (otherwise use die), or, better yet if you want to mimic exception-based code, use confess and/or your exception class hierarchy.
† Even just like die ExceptionClass->new(...);
Bear in mind that in the way of exceptions Perl only has the lonesome die, and eval. For more structure you'll need to implement it all, or use frameworks like Exception::Class or Throwable
‡ By writing and using a method that generates a plain string with useful information from the object, for Carp::confess $obj->stringify.
Or by overloading the "" (quote) operator for the class since it gets used when confess-ing an object (string context), for Carp::confess $obj; this is good to have anyway.
A basic example for both:
use overload ( q("") => \&stringify );
sub stringify {
my $self = shift;
join ", ", map { "$_ => " . ( $self->{$_} // 'undef' ) } keys %$self
}
where instead of a reference to a named sub on can directly write an anonymous sub.
As a way of solving the OP's problem, but with a different module, if you use Nice::Try instead, you will get the result you expect:
use Carp;
use Nice::Try;
try {
foo();
}
catch {
# do something before die
die $_;
} # this is line 10
sub foo {
croak 'die'; # this is line 13
}
You get:
die at ./try-catch-and-croak.pl line 13.
main::foo() called at ./try-catch-and-croak.pl line 4
main::__ANON__ called at ./try-catch-and-croak.pl line 7
eval {...} called at ./try-catch-and-croak.pl line 7 ...propagated at ./try-catch-and-croak.pl line 9.
For full disclosure, I am the author behind Nice::Try

Wrapping Perl "die" and "warn" in a utility subroutine

I want to write a small subroutine that can decorate all error messages in a consistent way instead of having to copy it all around my program.
However I want the line numbers to be from where it was called, not from where the die/warn occurred.
In C I would just use a preprocessor macro, but Perl does not have those. What is the best way to implement this?
Use Carp for warnings/errors. You can use __WARN__ and __DIE__ hooks to affect what warn prints to the STDERR stream and how die is thrown. Note that they are quite different.
use warnings;
use strict;
use feature 'say';
use Carp;
$SIG{__WARN__} = \&wrap_warn;
sub wrap_warn {
print "WARNING: #_";
}
sub level_2 {
say "Print from level_2";
carp "carp from level_2(#_)";
}
sub level_1 {
level_2(#_);
}
level_1("from main");
prints to STDOUT
Print from level_2
WARNING: carp from level_2(from main) at wrap_warn.pl line 19.
main::level_2('from main') called at wrap_warn.pl line 15
main::level_1('from main') called at wrap_warn.pl line 22
If you want this to still go to STDERR then use print STDERR "WARNING: #_";
Make sure to carefully read about %SIG in perlvar and warn, at least.
While it seems that you want this to be global, I'd like to mention that one generally wants to local-ize changes like this one. There's an example in this post, and more out there.
Adding the following will add stack traces to exceptions and warnings:
use Carp::Always;
For the occasional use, use the following to avoid modifying your program:
perl -MCarp::Always script args
or
PERL5OPT=-MCarp::Always script args

in perl, 'use strict' disables important warnings

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 '$#`.
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";

How can I suppress warnings from a Perl function?

In PHP you might use # in front of function call to suppress warnings returned.
Is there something similar in Perl?
This feature of PHP is crazy and should be avoided whenever possible.
Perl has two kinds of exceptions: Fatal errors and warnings. Warnings may either be emitted by Perl itself, or by user code.
Inside a certain static/lexical scope, Perl's builtin warnings can be switched off like:
use warnings;
foo();
sub foo {
no warnings 'uninitialized'; # recommended: only switch of specific categories
warn "hello\n";
1 + undef; # Otherwise: Use of uninitialized value in addition (+)
}
Output: hello on STDERR.
(A list of all warnings categories can be found here )
But this can't be used to remove warnings from code you are calling (dynamic scope). This also doesn't silence user-defined warnings.
In this case, you can write a handler for the __WARN__ pseudo-signal:
use warnings;
{
local $SIG{__WARN__} = sub { };
foo();
print "bye\n";
}
sub foo {
warn "hello\n";
1 + undef;
}
Output: bye on STDOUT.
We can abstract that into a function muffle:
sub muffle {
my $func = shift;
local $SIG{__WARN__} = sub { };
return $func->(#_);
}
muffle(\&foo, 1, 2, 3); # foo(1, 2, 3)
However, this is an incredibly dumb thing to do:
Warnings point to potential problems and bugs. Fix those instead of ignoring them.
Don't activate built-in warnings in the first place for categories you aren't interested in. E.g. many people are perfectly happy that an undef value stringifies to the empty string, and don't want any warning for that.
The strategies outlined here do not handle fatal exceptions, use Try::Tiny instead.
You could also just run perl -X and disable all warnings.
I think there are perfectly valid reasons for doing this FWIW.
Easier way is to use no warnings; See perldoc link for more information. Wrap the statement giving warning in curly braces to get rid of the warning message.
E.g.
{
no warnings;
<statement giving warning>
}

How do you best attribute errors in a Perl method to the caller

Given a method that may fail with warnings and/or errors, I want the error method to show up at the caller. Fir instance this script:
foo(0); # line 1
sub foo {
1 / shift; # line 4
}
Produces the error Illegal division by zero at foo.pl line 4, but I want Illegal division by zero at foo.pl line 1. There should be several ways if I put the method in a module or if I wrap the method body in eval, but I have not found an easy way like this:
sub foo {
attributeErrorsToCaller; # do some magic
1 / shift;
}
Is there such a way?
EDIT: mirod's answer comes close not what I was looking for:
Foo::foo(0); # line 1
package Foo;
use diagnostics -traceonly;
BEGIN { disable diagnostics; }
sub foo {
enable diagnostics;
1 / shift; # line 9
}
Without enable diagnostics the error message is Illegal division by zero at foo.pl line 9.. With enable diagnostics it is still too verbose, but this may also be useful:
Uncaught exception from user code:
Illegal division by zero at foo.pl line 10.
at foo.pl line 10
Foo::foo(0) called at foo.pl line 2
I bet I could hack diagnostics to get exactely the feature I want, but using diagnostics as raw module is probably more recommended.
Carp is very, very close to "do_some_magic" you are asking for. For instance:
#!/usr/bin/perl -w
use strict;
# I fork to be as close to natural die() as possible.
fork() or Foo::foo();
fork() or Foo::bar();
fork() or Foo::baz();
sleep 1;
package Foo;
use Carp;
sub foo { die "Some error (foo)"; };
sub bar { croak "Some error (bar)"; };
sub baz { bar(); };
As you can see, croak() acts almost like die(), but reports error to the caller (even indirectly -- see baz).
However, it won't handle 1/0 for you -- either use eval (or even Try::Tiny), or check input values* and say "division by zero" yourself.
Carp is standard, which means understandable by further maintainers of your code, and also can print neat stack traces via confess or cluck or even print Carp::longmess (see the doc).
*which is good anyway
Would use diagnostics; be enough for you? It will dump the call stack, so the caller is quite easy to find out.
For example in you example:
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
foo(0);
sub foo
{
return 1/$_[0];
}
gives this:
`Illegal division by zero at test_die line 12 (#1)
(F) You tried to divide a number by 0. Either something was wrong in
your logic, or you need to put a conditional in to guard against
meaningless input.
Uncaught exception from user code:
Illegal division by zero at test_die line 12.
at test_die line 12
main::foo(0) called at test_die line 8
Not like you describe. You can implement Debug::Trace to pull off a full back trace.
You may also find the perl caller which is quite useful for this type of debugging. But for a live application you will likely need to do more detailed tracing.
http://perldoc.perl.org/functions/caller.html