--- name: warn signature: 'warn LIST' since: 5.0 status: documented categories: ["I/O"] --- ```{index} single: warn; Perl built-in ``` *[I/O](../perlfunc-by-category)* # warn Emit a warning to `STDERR`. `warn` stringifies `LIST` and prints the result to `STDERR` — the same formatting machinery as [`die`](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 ```perl 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`](die), `warn` does **not** unwind. Execution continues with the statement after the call. ## Global state it touches - [`$@`](../perlvar) — read by the no-argument form. If [`$@`](../perlvar) holds a non-empty value, `warn` re-surfaces it (see *Propagation* below). `warn` does **not** write [`$@`](../perlvar). - [`$,`](../perlvar), [`$\`](../perlvar) — **not** consulted. `warn` is not [`print`](print); the output separators and record separator play no role. The message is written as a single string. - [`$.`](../perlvar) — the current input line number, appended to messages that lack a trailing newline. - [`$SIG{__WARN__}`](../perlvar) — if set, the handler runs in place of writing to `STDERR`. See *The `$SIG{__WARN__}` hook* below. - `STDERR` — the default destination. Any redirection of `STDERR` (shell-level `2>`, `open STDERR, ...`, a PerlIO layer) affects where `warn` output lands. ## The trailing-newline rule The same rule as [`die`](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, `", line M"`, then a final `"."` and newline. Use this when pinpointing the call site is more useful than a tidy message. ```perl 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 [`$@`](../perlvar): - If [`$@`](../perlvar) is **non-empty**, `warn` appends `"\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: ```perl eval { risky() }; warn if $@; # "\n\t...caught at ..." ``` - If [`$@`](../perlvar) is also empty, the string `"Warning: Something's wrong"` is used. This is deliberately asymmetric with [`die`](die): [`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 [`$@`](../perlvar). ## 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`](die), or dropping it on the floor: ```perl local $SIG{__WARN__} = sub { my ($msg) = @_; return if $msg =~ /^Use of uninitialized/; # silently drop log_warning($msg); }; ``` Three asymmetries with [`$SIG{__DIE__}`](../perlvar) are worth internalising: - **The default message is suppressed.** `$SIG{__DIE__}` runs *alongside* the exception machinery; `$SIG{__WARN__}` runs *instead of* the default `STDERR` write. If the handler does nothing, the warning is silently dropped. - **To pass the warning through, call `warn` again.** The handler is not re-entered for its own `warn` call, so there is no infinite loop: ```perl local $SIG{__WARN__} = sub { log_warning($_[0]); warn $_[0]; # re-emit to STDERR as well }; ``` - **A `__WARN__` handler can silence *mandatory* warnings** — warnings that `no warnings` cannot turn off. This makes `$SIG{__WARN__}` a sledgehammer; prefer `no warnings ''` for targeted suppression and reserve the handler for routing or escalation. ```perl # 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: - **`warn`** is a built-in function that emits a single message right now. You call it. - **`use warnings`** is 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 machinery `warn` uses. The pragma's diagnostics flow through `$SIG{__WARN__}` exactly like explicit `warn` calls. `no warnings ''` 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: ```perl open my $fh, "<", $path or warn "skipping $path: $!\n" and next; ``` Development-mode diagnostic with location appended: ```perl warn "unexpected record shape"; # unexpected record shape at parser.pl line 87. ``` Noticing a caught exception without suppressing it: ```perl eval { load_config() }; warn if $@; # surfaces "...caught at ..." ``` Route every warning through a logger, still printing to `STDERR`: ```perl local $SIG{__WARN__} = sub { my ($msg) = @_; $logger->warn($msg); print STDERR $msg; # preserve default visibility }; ``` Escalate a specific warning to a fatal error: ```perl 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): ```perl 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;` or `warn "";`) 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 to `STDERR` via its `""` overload (or Perl's default `MyClass=HASH(0x...)`). - **`warn` inside `$SIG{__WARN__}`**: does **not** re-enter the handler. The call writes to `STDERR` as if no handler were installed. This is what makes the "pass through" idiom safe. - **`warn` during global destruction**: still works, but `STDERR` may already be closed in pathological cases. Warnings from `DESTROY` handlers running at interpreter exit can vanish. - **`STDERR` closed or redirected**: `warn` writes to whatever `STDERR` currently points at. If `STDERR` is closed, the write fails silently; no error is raised, because `warn` itself does not check. - **No relation to [`$\`](../perlvar) / [`$,`](../perlvar)**: adding `local $\ = "\n"` does not make `warn "x"` print a newline. The trailing-newline rule is the only newline-adding mechanism for `warn`. ## Differences from upstream Fully compatible with upstream Perl 5.42. ## See also - [`die`](die) — same formatting rules (trailing-newline suppresses location, references pass through unchanged), but raises an exception instead of reporting and continuing - [`eval`](eval) — pairs with the no-argument form of `warn` for the "catch, inspect, re-surface" idiom - [`$@`](../perlvar) — the source the no-argument `warn` reports from - [`$SIG{__WARN__}`](../perlvar) — the hook that replaces the default `STDERR` write; use it for routing, filtering, or escalation - `Carp` — `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