http://qs321.pair.com?node_id=231014


in reply to Re^2: Best Practices for Exception Handling (no isa)
in thread Best Practices for Exception Handling

I like exceptions too. But it is a pain to use exceptions for all failures. Exceptions should be "exceptions" and not indications of a "normal" failure (at least, that is the most accepted practice in the areas I find myself working). The line between the two can be subtle.

Trying to open a file for reading when that file does not exist would not usually throw an exception because that is an expected failure mode. Getting an error when reading from a file (besides "end of file", which is sometimes described as an error) should throw an exception.

Aside: I find it interesting that you pick errors reading from files for your example. A few months back I was writing about best practices when reading files in Perl. I came to the conclusion that checking for non-end-of-file errors (that is, real errors) when reading from a file handle is just not worthwhile. 1) They are difficult to detect. 2) It is hard to imagine situations where such happens. 3) In the rare cases where it does happen, the best reaction is often to treat it like a premature end of file (except that it would be nice to note that the end of input processing was due to an error and what that error was). So I'd love to see the read primitives of Perl issue a warning if they "fail" for reasons other than end-of-file. But I'm not sure that throwing an exception for that case would be the best choice.

So I'd be interested in hearing about the "nasty bugs" that you've run into related to read failures.

So what is an exception and what is a "normal failure"? There are two ends to the spectrum, of course. Perl is close to the "all failures are normal" end, only throwing exceptions for extreme things like compilation failure. Perl 6 sounds like it will be close to the "all failures are exceptions" end.

The problem with the former is that it is way too easy to forget to check for failure and so failures get ignored when they shouldn't. The problem with the latter is that it can be inconvenient to put catch blocks everywhere you should -- though this "problem" probably leads to better programming.

So the case is pretty clear that we should go the route of Perl 6 and have all failures be exceptions. I'll probably agree except that this is Perl 5 and so most failures aren't going to throw exceptions, most Perl 5 programmers aren't used to dealing with exceptions, and Perl puts a big emphasis of programmer convenience. So in Perl 5, I want to drive down the middle of the road on this point.

Which brings us back to: What is an exception and what is a "normal failure"? Take the "trying to open a non-existant file for reading" example. In the general case, it would be inconvenient for Perl 5 to throw an exception for this. In specific cases, you do want to throw an exception for this. The usual idiom for distinguishing the two cases is:

open( FILE, "<read.me" ) or die "Can't read read.me: $!\n";
versus
if( ! open( FILE, "<read.me" ) ) { # Deal with the absense of this file }
which begs the question, what should be done with this:
open( FILE, "<read.me" );
In Perl 5, the answer is simply that this code is broken and should be fixed to one of the previous two cases. My answer is that Perl 5 is "broken" and should treat this like the first case automatically.

And that is the point of my design for an error object. It makes it convenient to treat a failure as normal but automatically converts a failure into an exception when it should.

So part of the point of my error object is to make it easy to generate exceptions for failures. So you should like it. The difference between my approach and yours is that my approach allows each caller to decide (or to not even think about it in which case the decision is made for them) what is normal failure and what is an exception. In your approach, the callee makes that decision for everyone and forces them to convert between the two cases when that decision doesn't match their situation.

And the problems with converting are: 1) Converting from exception to handled failure is inconvenient in Perl 5. 2) Converting from normal failure to exception usually requires that the caller construct the error message when the callee usually is in a better position to do that. But the error object forces the callee to construct a useful error message while also allowing the caller to add to it (or ignore it).

                - tye

Replies are listed 'Best First'.
Re^4: Best Practices for Exception Handling (no isa)
by adrianh (Chancellor) on Jan 29, 2003 at 20:03 UTC

    My bias lies towards the "all errors are exceptions" end of the spectrum :-) For me it helps more than it hinders, but I understand the distinction that you're making between "normal" and "exceptional" results.

    The nasty bugs caused by read all fall under the general heading of "files that should have been read totally being truncated". One instance was especially amusing since they "just knew" that the problem was with a bit of networking code that was moving the result of the read over the wire. They'd spent a week trying to track down an intermittant networking error, rather than the obvious (in hindsight) intermittant read problem.

    In general I like your idea - think it would make an interesting alternative to Fatal.

    However, the problem of dealing with subroutines that return false values "normally" means that it's not as useful in these cases since you have to make an explicit check for the error condition.

    For me, the inconvenience of the perl5 exception "syntax" is worth the other advantages it gives me.

Re: Re^3: Best Practices for Exception Handling (no isa)
by zby (Vicar) on May 12, 2003 at 13:03 UTC
    For me exception is a language construct - a flow of logic. While what is an error and what is 'normal failure' is defined by a particular program. I would rather expect that you'll find many situations other than error conditions where using exceptions would be beneficial. Of course you can argue that the exception construct is particulary well suited for errors, and not for 'normal failures', it just seems to me like mixing semantical levels when you distinguish between exceptions and 'normal' failures.