Perl Warnings and the Warn Function
This article explains the difference between Perl’s warnings and the warn function. Read on to find out the difference and use the code to fix your issues!
Join the DZone community and get the full member experience.
Join For FreeI mentioned in passing last week that the next major release of Perl, v5.36, is set to enable warnings
by default for code that opts in to use v5.35;
or above. Commemorating Perl’s 34th birthday the week before that, I noted that the warnings system has been getting ever finer-grained since its introduction in 2000. And, fellow Perl blogger and CPAN author Tom Wyant has been cataloging his favorites over the past several months — the latest as of this writing was on the “ambiguous” category of warnings, and you can find links to previous entries in his series at the bottom of that post.
It occurred to me afterward that there may be some confusion between the warnings
pragma and the related warn
function for reporting arbitrary runtime errors. warn
outputs its arguments to the standard error (STDERR
) stream, or if it’s not given any then you get a string with any exception from ( under use English
) followed by a tab and then “...caught at <file> line x.
” If that’s empty too, a plain warn
just says, “Warning: something's wrong at <file> line x.
”, which isn’t exactly helpful, but then again you didn’t give it much to go on.
warn
output doesn’t have to go to STDERR
, and this is where the relation to the warnings pragma comes in because both are governed by the __WARN__
signal handler in the %SIG
hash. Normally, you might opt to only display runtime warnings if a debugging flag is set, like so:
#!/usr/bin/env perl
use strict;
use warnings;
my $DEBUG = 0;
$SIG{__WARN__} = sub { warn @_ if $DEBUG };
warn 'shhh'; # silenced
$DEBUG = 1;
warn 'hello warnings';
But, if you set that signal handler in a BEGIN
block, it catches compile-time warnings too, in which case flipping a flag after the fact has no effect — the compiler’s already run:
#!/usr/bin/env perl
use strict;
use warnings;
my $DEBUG = 0;
BEGIN { $SIG{__WARN__} = sub { warn @_ if $DEBUG } }
my $foo = 'hello';
my $foo = 'world'; # no warning issued here
$DEBUG = 1;
my $foo = 'howdy'; # still nothing
By the way, both __WARN__
and __DIE__
hooks are also used by the Carp module and its friends, so you can use the same technique with their enhanced output:
#!/usr/bin/env perl
use strict;
use warnings;
use Carp qw(carp cluck);
my $DEBUG = 0;
BEGIN { $SIG{__WARN__} = sub { warn @_ if $DEBUG } }
carp 'quiet fish';
$DEBUG = 1;
loud_chicken();
sub loud_chicken {
cluck 'here comes a stack trace';
}
You could use these as stepping stones towards a debug log for larger applications, but at that point, I’d suggest looking into one of the logging modules on CPAN like Log::Log4perl (not to be confused with that lately-problematic Java library), Log::Dispatch (which can be wired into Log4perl), or something else to suit your needs.
Cover image: "Warning!" by John Goodridge is licensed under CC BY-NC-SA 2.0
Published at DZone with permission of Mark Gardner, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments