Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much

Re^2: Best Practices for Exception Handling (no isa)

by adrianh (Chancellor)
on Jan 29, 2003 at 13:53 UTC ( #230944=note: print w/replies, xml ) Need Help??

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

Cute idea!

However, one of the reasons I prefer exceptions to returning any sort of error object is because they act outside the normal return path.

The problem with "false == failure" is that it falls down as soon as you have "false" as a legal return value. For example, people often misuse read because it has different meanings for a false return value (0 == EOF, undef == error). People forget to check for the error condition - leading to nasty bugs.

The same sort of thing applies to any sort of "funny" return value - which in hindsight was why I was uncomfortable with the code I wrote in Test::Exception extension with (evil?) overloading :-)

With exceptions you don't have to worry about any confusion between legal return values and errors.

Another advantage of exceptions is that I can separate my error handling code from the error producing code, which makes things like massaging errors between different application tiers so much easier.

Replies are listed 'Best First'.
Re^3: Best Practices for Exception Handling (no isa)
by tye (Sage) on Jan 29, 2003 at 17:03 UTC

    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, "<" ) or die "Can't read $!\n";
    if( ! open( FILE, "<" ) ) { # Deal with the absense of this file }
    which begs the question, what should be done with this:
    open( FILE, "<" );
    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

      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.

      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.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://230944]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (7)
As of 2021-10-27 10:22 GMT
Find Nodes?
    Voting Booth?
    My first memorable Perl project was:

    Results (91 votes). Check out past polls.