Hack 91. Write Less Error-Checking Code


Identify runtime errors without writing code.

One of the less-endearing features of working with the outside world is that things can fail: you might run out of disk space, lose your network connection, or have some other sort of serious error. Robust programs check for these errors and retry or fail gracefully as necessary. Of course, checking every potential point of failure for every possible failure can make a lot of repetitive code.

Fortunately, Perl provides a way to fail on errors without having to check for them explicitlythe Fatal core module.

The Hack

One of the most failure-prone points of programming is IO programming, whether working with files or other computers across a network. File paths may be wrong, file permissions may change, disks can mysteriously fill up, and transitory networking problems may make remote computers temporarily invisible. If you work much with files, using Fatal can reduce the amount of code you need to write.

The Fatal module takes a list of function names to override to raise exceptions on failures. open and close are good candidates. Pass their names to the use line to avoid writing the or die( ) idiom:

use Fatal qw( open close ); open( my $fh, '>', '/invalid_directory/invalid_file' ); print {$fh} "Hello\\n"; close $fh;

If you run this (and don't have a directory named /invalid_directory), you'll receive an error message:

Can't open(GLOB(0x10159d74), >, /nodirectory/nofile.txt): No such file or   directory at (eval 1) line 3   main::__ANON__('GLOB(0x10159d74)', '>', '/nodirectory/nofile.txt') called       at fatal_io.pl line 8

If it's appropriate for your program to exit with an error if this happens, this is all you need to do. To handle the error with more grace, wrap the code in an eval block and do what you need to do:

use Fatal qw( open close ); eval {     open( my $fh, '>', '/invalid_directory/invalid_file' );     print {$fh} "Hello\\n";     close $fh; }; die "File error: $!" if $@;

Of course, nothing says that your code must do something with the caught exceptionbut at least consider how robust your code should be.


Hacking the Hack

Fatal can also make your own code strict. Use it within your own modules just as you would normally:

package MyCode; sub succeed { 1 } sub fail    { 0 } use Fatal qw( :void succeed fail ); succeed( ); fail( ); 1;

Because fail( ) returns false, Fatal throws an exception. This code has one trick, in that the subroutine declarations come before the Fatal call. If you use the module before Perl parses the subroutine declarations, Fatal will not be able to find them and will throw an error.

This can be useful for your own code, but it's even more useful when you export these functions to other code. The order of the use lines doesn't matter here, though:[6]

[6] See "Understand What Happens When" [Hack #70] to learn why.

package MyCode; use base 'Exporter';                our @EXPORT = qw( succeed fail ); sub succeed { 1 } sub fail    { 0 } use Fatal qw( :void succeed fail ); 1;

This technique even works with classes and objects; you don't have to export your methods for Fatal to work.



Perl Hacks
Perl Hacks: Tips & Tools for Programming, Debugging, and Surviving
ISBN: 0596526741
EAN: 2147483647
Year: 2004
Pages: 141

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net