Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I conditionally make warnings fatal?

Tags:

perl

I want to have fatal errors that can be demoted to warnings (or conversely, warnings that can be promoted to fatal errors) depending on the user's preference. At present, I'm using die and overriding it like this:

my $force;
BEGIN {
    no warnings 'once';
    Getopt::Long::Configure('pass_through');
    GetOptions('force', \$force);
    *CORE::GLOBAL::die = sub { warn @_ } if $force;
    Getopt::Long::Configure('no_pass_through');
}

use My::Module;
...
die "maybe";
...
exit(1) if $force;
exit(0); # success!

I don't like this approach, mostly because there are a few places where I still want to die (e.g. missing command-line arguments). I'd rather change (most) instances of die to warn and do a conditional use warnings FATAL => 'all'1. The problem is that use warnings is lexically scoped, so this is ineffective:

if (!$force) {
    use warnings FATAL => 'all';
}

Attempting to use a postfix conditional is a syntax error:

use warnings FATAL => 'all' unless $force;

and use can't be used in an expression:

$force or use warnings FATAL => 'all';  # syntax error

I can think of various distasteful work-arounds (Defining my own warn/die, duplicating my main script code in an if/else, etc.) but am seeking an elegant solution that conditionally applies use warnings in the current lexical scope. (Applying it in the parent scope would work as well but would likely require dark magic.)


1: Actually, I want to add use warnings::register to my modules and use warnings FATAL => 'My::Module' to my script, but the distinction is unimportant for the purposes of this question.
like image 855
Michael Carman Avatar asked Oct 17 '25 15:10

Michael Carman


1 Answers

You could try:

use if !$force, warnings => qw( FATAL all );

Yes, there's a module called if that is distributed with Perl to make it really easy to do conditional imports.

Note that this is evaluated at compile time, so $force needs to be defined at compile time. (Probably within a BEGIN { ... } block.) Based on the code samples in your question, you seem to have figured that part out already though.

Alternatively, more manual:

BEGIN {
    require warnings;
    warnings->import(qw/ FATAL all /) unless $force;
}

A completely different approach would be to use a signal handler $SIG{__WARN__} or $SIG{__DIE__} to decide to die or not at run-time.

like image 100
tobyink Avatar answered Oct 20 '25 16:10

tobyink