Perl Programming Page 4 - Returns and Perl Subroutines |
Use a bare return to return failure. Notice that each final return statement in the examples of the previous guideline used a return keyword with no argument, rather than a more-explicit return undef. Normally, relying on default behaviour is not best practice. But in the case of areturnstatement, relying on the default return value actually prevents a particularly nasty bug. The problem with returning an explicit return undef is that—contrary to most people’s expectations—a returned undef isn’t always false. Consider a simple subroutine like this: use Contextual::Return; sub guesstimate{ my @estimates; # [Acquire data for specified criterion] return undef if $failed; # [Do guesswork based on the acquired data] # Return all guesses in list context or average guess in scalar context... The successful return values are both fine, and completely appropriate for the two contexts in which the subroutine might be called. But the failure value is a serious problem. Sinceguesstimate()specifically tests for calls in list context, it’s obvious that the subroutine is expected to be called in list contexts: if (my @melt_rates = guesstimate('polar melting')) { for my $interval (1,2,5,10,50,100,500) { But if the guesstimate() subroutine fails, it returns a single scalar value: undef. And in a list context (such as the assignment to @melt_rates), that single scalar undef value becomes a one-element list: (undef). So @melt_rates is assigned that one-element list and then evaluated in the overall scalar context of the if condition. And in scalar context an array always evaluates to the number of elements in it, in this case 1. Which is true. Oops!* What should have happened, of course, is thatguesstimate()should have returned a failure value that was false in whatever context it was called, i.e.,undefin scalar context and an empty list in list context: if ($failed) { But that’s precisely what areturnitself does when it’s not given an argument: it returns whatever the appropriate false value is for the current call context. So, by always using a barereturnto return a “failure value”, you can ensure that you will never bring about the destruction of the entire planetary ecosystem because of an expectedly trueundef. Meanwhile, Chapter 13 presents a deeper discussion on the most appropriate ways to propagate failure from a subroutine. * Yep, that’s the sound of alarm bells you’re hearing. † And if that sample happens to be an integer, then $found will be assigned a numeric value, exactly as expected. It will be the wrong numeric value, but hey, at least that will make the bug much more interesting to track down. * They’d be the “edge-cases”, except that, in this instance, they’re conceptually in the middle of possibilities. * And here “Oops!” means: theifblock executes despite the failure ofguesstimate()to acquire any meaningful data. So, when the climate model requests a numerical polar melting rate, thatundefis silently converted to zero. This dwimmery causes the model to show that polar melting rates have absolutely no connection to world climate in general, and to rising ocean levels in particular. So mankind can happily keep burning fossil fuels at an ever-greater rate, secure in the knowledge that it has no effect. Until one day, the only person left is Kevin Costner. On a raft.
blog comments powered by Disqus |
|
|
|
|
|
|
|