The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

warnings::everywhere - a way of ensuring consistent global warning settings

VERSION

This is version 0.022.

SYNOPSIS

 # Turn off run-time warnings
 use strict;
 use warnings;
 no warnings::anywhere qw(uninitialized);
 
 use Module::That::Spits::Out::Warnings;
 use Other::Unnecessarily::Chatty::Module;

 use warnings::everywhere qw(uninitialized);
 # Write your own bondage-and-discipline code that really, really
 # cares about the difference between undef and the empty string
 
 # Stop "helpful" modules from turning compile-time warnings back on again
 use strict;
 use warnings;
 no warnings::anywhere {
     warning       => 'experimental::smartmatch',
     thwart_module => [qw(Moose Moo Dancer Dancer2)],
 };
 use Module::That::Might::Pull::In::Moose::Or::Moo::Or::Who::Knows::What;
 
 given (shift @ARGV) {
     ...
     default {
         print STDERR "# I'll fix it in a moment, OK?\n";
     }
 }

DESCRIPTION

Warnings are great - in your own code. Tools like prove, and libraries like Moose and Modern::Perl, turn them on for you so you can spot things like ambiguous syntax, variables you only used once, deprecated syntax and other useful things.

By default use warnings turns on all warnings, including some that you might not care about, like uninitialised variables. You could explicitly say

 use warnings;
 no warnings qw(uninitialized);

or you could use a module like common::sense which disables some warnings and makes others fatal, or you could roll your own system. Either way, for your own code, there are plenty of ways around unwanted warnings.

Not so for other code, though.

The test suite at $WORK produces a large number of 'use of uninitialized variable' warnings from (at the last count) four separate modules. Some of them are because warnings got switched on for that module, even though the module itself didn't say anything about warnings (probably because the test suite was run with prove). Others are there because the module explicitly said use warnings, and then proceeded to blithely throw around variables without checking whether they were defined first.

Either way, this isn't my code, and it's not something I'm going to fix. These warnings are just spam.

Similarly, if you disable e.g. experimental::smartmatch because you know that you're using smartmatch, and you're not going to be using a version of Perl that has a version of smartmatch that behaves differently, you might get those warnings enabled back again by a module such as Moose or Dancer which turns all warnings on.

This is where warnings::everywhere comes in.

Usage

Run-time warnings

At its simplest, say

 use warnings::everywhere qw(all);

and all modules imported from there onwards will have all warnings switched on. Modules imported previously will be unaffected. You can turn specific warnings off by saying e.g.

 no warnings::everywhere qw(uninitialized);

or, depending on how frustrated and/or grammatically-sensitive you happen to be feeling,

 no warnings::anywhere qw(uninitialized);

or

 no goddamn::warnings::anywhere qw(uninitialized);

Parameters are the same as use warnings: a list of categories as per perllexwarn, where all means all warnings.

Compile-time warnings

This won't work for some (all?) compile-time warnings that are not just enabled for the module in question, but are injected back into your package. Moose, Moo, Dancer and Dancer2 all do this at the time of writing, by saying warnings-import> in their import method, thus injecting all warnings into your package.

To stop such code from turning back on warnings that you thought you'd disabled, say e.g.

 no warnings::anywhere {
     warning       => 'experimental::smartmatch',
     thwart_module => [qw(Moose)],
 };

Warning: warnings::everywhere disables these warnings by what is basically a source filter, so use with caution. If you can find an approved way of preventing modules such as Moose from doing this, do that rather than messing about with the module's source code!

Limitations

warnings::everywhere works by fiddling with the contents of the global hashes %warnings::Bits and %warnings::DeadBits. As such, there are limitations on what it can and cannot do:

It cannot affect modules that are already loaded.

If you say

 use Chatty::Module;
 no warnings::anywhere qw(uninitialized);

that's no good - Chatty::Module has already called use warnings and uninitialized variables was in the list of enabled warnings at that point, so it will still spam you.

Similarly, this is no help:

 use Module::That::Uses::Chatty::Module;
 no warnings::anywhere qw(uninitialized);
 use Chatty::Module;

Chatty::Module was pulled in by that other module already by the time perl gets to your use statement, so it's ignored.

It's vulnerable to anything that sets $^W

Any code that sets the global variable $^W, rather than saying use warnings or warnings-import>, will turn on all warnings everywhere, bypassing the changes warnings::everywhere makes. This also includes any code that sets -w via the shebang.

Any change to warnings by any of the warnings::anywhere code will turn off $^W again, whether it's a use statement or an explicit call to disable_warning_category or similar.

Any module that claims to enable warnings for you is potentially suspect - Moose is fine, but Dancer sets $^W to 1 as soon as it loads, even if your configuration subsequently disables import_warnings.

It cannot make all modules use warnings

All it does is fiddle with the exact behaviour of use warnings, so a module that doesn't say use warnings, or import a module that injects warnings like Moose, will be unaffected.

It's not lexical

While it looks like a pragma, it's not - it fiddles with global settings, after all. So you can't say

 {
     no warnings::anywhere qw(uninitialized);
     Chatty::Module->do_things;
 }
 Unchatty::Module->do_stuff(undef);

and expect to get a warning from the last line. That warning's been turned off for good.

Its method of disabling compile-time warnings is frankly iffy

The best I can say about its method of messing with the source code of imported modules is that at least its modifications shouldn't stack with other source filters, so the degree of weirdness and potential insanity should be reduced to a manageable level.

SUBROUTINES

warnings::anywhere provides the following functions, mostly for diagnostic use. They are not exported or exportable.

categories_enabled
 Out: @categories

Returns a sorted list of warning categories enabled globally. Before you've fiddled with anything, this will be the list of warning categories from perllexwarn, minus all which isn't a category itself.

Fatal warnings are ignored for the purpose of this function.

categories_disabled
 Out: @categories

Returns a sorted list of warning categories disabled globally. Before you've fiddled with anything, this will be the empty list.

Fatal warnings are ignored for the purpose of this function.

enable_warning_category
 In: $category

Supplied with a valid warning category, enables it for all future uses of use warnings.

disable_warning_category
 In: $category

Supplied with a valid warning category, disables it for future uses of use warnings - even calls to explicitly enable it.

TO DO

Support for fatal warnings, possibly. It's possible it doesn't behave correctly when passed 'all'.

DIAGNOSTICS

Unrecognised warning category $category

Your version of Perl doesn't recognise the warning category $category. Either you're using a different version of Perl than you thought, or a third-party module that defined that warning isn't loaded yet.

SEE ALSO

common::sense

AUTHOR

Sam Kington <skington@cpan.org>

The source code for this module is hosted on GitHub https://github.com/skington/warnings_everywhere - this is probably the best place to look for suggestions and feedback.

COPYRIGHT

Copyright (c) 2013 Sam Kington.

LICENSE

This library is free software and may be distributed under the same terms as perl itself.