warn#
Emit a warning to STDERR.
warn stringifies LIST and prints the result to STDERR — the
same formatting machinery as die, minus the unwind. Control
returns to the caller; nothing is thrown, nothing is caught. Reach
for it when the program should keep running but the user, the
operator, or the log deserves to hear about something unexpected.
Synopsis#
warn LIST
warn $message
warn # re-surface current $@ as a warning
What you get back#
warn returns 1 under normal circumstances. The return value is
almost never useful — the point of the call is the side effect on
STDERR (or on whatever $SIG{__WARN__} does with the message).
Unlike die, warn does not unwind. Execution continues
with the statement after the call.
Global state it touches#
$@— read by the no-argument form. If$@holds a non-empty value,warnre-surfaces it (see Propagation below).warndoes not write$@.$,,$\— not consulted.warnis notprint; the output separators and record separator play no role. The message is written as a single string.$.— the current input line number, appended to messages that lack a trailing newline.$SIG{__WARN__}— if set, the handler runs in place of writing toSTDERR. See The$SIG{__WARN__}hook below.STDERR— the default destination. Any redirection ofSTDERR(shell-level2>,open STDERR, ..., a PerlIO layer) affects wherewarnoutput lands.
The trailing-newline rule#
The same rule as die applies, and for the same reason:
Message ends in
"\n"— used verbatim. Nothing is appended. Use this for warnings that are complete user-facing diagnostics.Message does not end in
"\n"— Perl appends" at FILE line N", and if a file is being read,", <HANDLE> line M", then a final"."and newline. Use this when pinpointing the call site is more useful than a tidy message.
warn "cache is stale\n"; # "cache is stale\n"
warn "cache is stale"; # "cache is stale at main.pl line 42.\n"
Reference-valued warnings never get location information appended. Stringifying an object to add file and line would defeat the point of passing one.
Propagation: warn with no argument (or empty string)#
When LIST is empty or stringifies to "", warn does not emit a
fresh message — it re-surfaces whatever is in $@:
If
$@is non-empty,warnappends"\t...caught"to it and emits the result. This is the canonical way to notice that an exception was caught without letting it die silently:eval { risky() }; warn if $@; # "<whatever died>\n\t...caught at ..."
If
$@is also empty, the string"Warning: Something's wrong"is used.
This is deliberately asymmetric with die: die with no
argument re-throws (triggering the propagation machinery and the
PROPAGATE hook for objects); warn with no argument reports
what is already in $@.
The $SIG{__WARN__} hook#
Setting $SIG{__WARN__} installs a handler that runs instead of
the default write to STDERR. The handler receives the exception
derived from LIST as its single argument and is responsible for
disposing of it — logging it, rewriting it, escalating it to
die, or dropping it on the floor:
local $SIG{__WARN__} = sub {
my ($msg) = @_;
return if $msg =~ /^Use of uninitialized/; # silently drop
log_warning($msg);
};
Three asymmetries with $SIG{__DIE__} are worth
internalising:
The default message is suppressed.
$SIG{__DIE__}runs alongside the exception machinery;$SIG{__WARN__}runs instead of the defaultSTDERRwrite. If the handler does nothing, the warning is silently dropped.To pass the warning through, call
warnagain. The handler is not re-entered for its ownwarncall, so there is no infinite loop:local $SIG{__WARN__} = sub { log_warning($_[0]); warn $_[0]; # re-emit to STDERR as well };
A
__WARN__handler can silence mandatory warnings — warnings thatno warningscannot turn off. This makes$SIG{__WARN__}a sledgehammer; preferno warnings '<category>'for targeted suppression and reserve the handler for routing or escalation.
# wipe out *all* compile-time warnings, then switch on at runtime
BEGIN { $SIG{'__WARN__'} = sub { warn $_[0] if $DOWARN } }
my $foo = 10;
my $foo = 20; # duplicate-my silenced
$DOWARN = 1;
warn "\$foo is alive and $foo"; # now shows up
warn the built-in vs. use warnings#
These are different things. Do not confuse them:
warnis a built-in function that emits a single message right now. You call it.use warningsis a pragma that enables categories of compile-time and run-time diagnostics (uninitialized values, deprecated features, unopened filehandles, and so on). The compiler and interpreter emit those diagnostics on your behalf, using the same machinerywarnuses.
The pragma’s diagnostics flow through $SIG{__WARN__} exactly like
explicit warn calls. no warnings '<category>' suppresses the
pragma’s diagnostics in its lexical scope but has no effect on an
explicit warn you wrote yourself — that call always fires.
Examples#
Report a recoverable problem and keep going:
open my $fh, "<", $path
or warn "skipping $path: $!\n" and next;
Development-mode diagnostic with location appended:
warn "unexpected record shape";
# unexpected record shape at parser.pl line 87.
Noticing a caught exception without suppressing it:
eval { load_config() };
warn if $@; # surfaces "...caught at ..."
Route every warning through a logger, still printing to STDERR:
local $SIG{__WARN__} = sub {
my ($msg) = @_;
$logger->warn($msg);
print STDERR $msg; # preserve default visibility
};
Escalate a specific warning to a fatal error:
local $SIG{__WARN__} = sub {
die @_ if $_[0] =~ /corrupt database/;
warn @_; # everything else: default path
};
Pass a blessed object for structured warnings (the receiver of a
$SIG{__WARN__} hook gets the reference, not a stringified form):
local $SIG{__WARN__} = sub {
my ($w) = @_;
if (ref($w) && $w->isa('MyApp::Warning')) {
$logger->record($w);
}
else {
print STDERR $w;
}
};
warn MyApp::Warning->new(code => 'SLOW_IO', detail => $path);
Edge cases#
List with two or more items is stringified and concatenated:
warn "bad record ", $n, ": ", $raw. The newline rule applies to the concatenated result.Empty list (
warn;orwarn "";) triggers the propagation path, not a fresh message.Reference-valued warning inside a
$SIG{__WARN__}handler: the handler receives the reference unchanged. If no handler is installed, the reference is stringified toSTDERRvia its""overload (or Perl’s defaultMyClass=HASH(0x...)).warninside$SIG{__WARN__}: does not re-enter the handler. The call writes toSTDERRas if no handler were installed. This is what makes the “pass through” idiom safe.warnduring global destruction: still works, butSTDERRmay already be closed in pathological cases. Warnings fromDESTROYhandlers running at interpreter exit can vanish.STDERRclosed or redirected:warnwrites to whateverSTDERRcurrently points at. IfSTDERRis closed, the write fails silently; no error is raised, becausewarnitself does not check.No relation to
$\/$,: addinglocal $\ = "\n"does not makewarn "x"print a newline. The trailing-newline rule is the only newline-adding mechanism forwarn.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
die— same formatting rules (trailing-newline suppresses location, references pass through unchanged), but raises an exception instead of reporting and continuingeval— pairs with the no-argument form ofwarnfor the “catch, inspect, re-surface” idiom$@— the source the no-argumentwarnreports from$SIG{__WARN__}— the hook that replaces the defaultSTDERRwrite; use it for routing, filtering, or escalationCarp—carp,cluck,croak,confess: warnings and exceptions that report from the caller’s perspective rather than the call site, which is almost always what a library wants