13.3. Contextual Failure
The Fatal pragma can also be invoked with the special marker :void. Loading Fatal with this extra marker causes it to rewrite builtins and subroutines in a slightly different way, such that they throw a failure exception only if they were called in a void context. Under :void, they continue to silently return false in non-void contexts. That is: use Fatal qw( :void open close ); if (open my $out, '>', $filename) { # Call to open( ) in non-void context so # open( ) returns false on failure open my $in, '<', '$filename.dat'; # Call to open( ) in void context so # open( ) throws exception on failure print {$out} <$in>; close $out # Call close( ) in non-void context so or carp "close failed: $OS_ERROR"; # close( ) returns false on failure close $in; # Call close( ) in void context so # close( ) throws exception on failure } While this may seem like an improvement (more flexible, more Perlish), it's actually a step backwards in terms of code reliability. The problem is that it's far too easy to call a subroutine or function in a non-void context and still not actually test it. For example: # Change unacceptable failure behaviour to throw exceptions instead... use Fatal qw( :void locate_and_open ); # and later... for my $filename (@source_files) { my $fh = locate_and_open($filename); my $head = load_header_from($fh); print $head; } Here, locate_and_open( ) is upgraded to throw exceptions on void-context failure. Unfortunately, it isn't called in a void context. It's called in scalar context, so it still returns its usual undef-on-failure. But, once again, the return value isn't subsequently checked. Non-void context doesn't always imply a test, so a use Fatal qw( :void funcname ) may make your code appear to be more robust, without actually making that code more robust...which makes that code less robust. |