Previous Page
Next Page

13.6. Reporting Failure

Have exceptions report from the caller's location, not from the place where they were thrown.

If someone is using a subroutine you wrote:


    use Data::Checker qw( check_in_range );

    for my $measurement ( @remote_samples ) {
        check_in_range($measurement, {min => 0, max => $INSTRUMENT_MAX_VAL});
    }

they're not going to want to encounter an exception like this:

    Value 24536526 is out of range (0..99) at /usr/lib/perl/Data/Checker.pm line 1345

The message itself is fine, but the location information is close to useless. Developers who are using your code don't care where your code detected a problem; all they care about is where their code caused the problem. They want to see something like:


    Value 24536526 is out of range (0..99) at reactor_check.pl line 23

That is, they want to be told the location where the fatal subroutine was called, not the internal location where it actually threw the exception.

And, of course, that's the whole purpose of the standard Carp module: to report exceptions from the caller's point of view. So never use die to throw an exception:

    die "Value $val is out of range ($min..$max)"
        if $val < $min || $val > $max;

Always use croak( ) instead:


    use Carp;

    
# and later...
croak( "Value $val is out of range ($min..$max)" ) if $val < $min || $val > $max;

The only situation when die could reasonably be used instead of croak( ) is if the error is a purely internal problem within your code, and not the caller's fault in any way. For example, if your subroutine is supposed to generate a result within a certain range using a very complicated process, you might choose to test whether the result was valid before returning it, like so:


    die "Internal error: somehow generated an inconsistent result ($result)"
        if $result < $min || $result > $max;

    return $result;

The simple rule of thumb here is that any exception message thrown with a die should always start with the words: 'Internal error:...'.

However, even in the case of internal errors, it can still better to use croak( ):


    croak "Internal error: somehow generated an inconsistent result ($result)"
        if $result < $min || $result > $max;

    return $result;

For a start, reporting the internal error from the caller's point of view allows developers to work out where their code is affected by your bug (in other words, where they'll have to devise a workaround).

More importantly, the Carp module provides a special 'verbose' option, which can be activated from the command line:

    >
     perl -MCarp=verbose bug_example.pl

Running a program with this mode enabled causes every call to croak( ) to provide a full stack back-trace after the error message. For example, instead of a message like:


    Internal error: inconsistent data format at 'bug_example.pl' line 33

under the "verbose" option, you would be given the full context of the failed call, including subroutine arguments:


    Internal error: inconsistent data format at /usr/lib/perl/Data/Loader.pm line 58
            Data::Loader::get('income.stats') called at ./Stats/Demography.pm line 2346
            Stats::Demography::get_stats_from('income.stats','CODE(0x80ec54)')
            called at 'bug_example.pl' line 33

By always reporting internal errors via croak( ), you make it easier for developers to cope with them at the time, and easier for you to debug them later (without having to modify your module's code to do so).

All the preceding arguments apply to warning messages, too. So always report warning messages using the carp( ) subroutine, instead of the built-in warn.

    Previous Page
    Next Page