http://qs1969.pair.com?node_id=491423

bradcathey has asked for the wisdom of the Perl Monks concerning the following question:

Fellow Monasterians:

I know that the Perlish way to handle an errors, like writing to a file, is to die, print the error $!, and take the forced exit. However, because I am writing commercial end-user web apps, I can't just exit—I need to put the best face on the error and keep the program going. In review, this is what I was taught:

... open UPLOADFILE, ">$upload_dir/$filename" or die "$!\n"; ...

However, this is basically what I have been doing instead:

my $error = uploader($dir, $name); print $error if ($error); sub uploader { my ($upload_dir, $filename) = @_; ... open UPLOADFILE, ">$upload_dir/$filename" or return("There was a pr +oblem uploading your file: $!"); ... }

Is it "safe" or "good practice" not to die? Or is there some intrinsic value of die that I am missing by not using it? Thanks all!


—Brad
"The important work of moving the world forward does not wait to be done by perfect men." George Eliot

Replies are listed 'Best First'.
Re: Friendly error trapping
by davidrw (Prior) on Sep 13, 2005 at 00:23 UTC

      I did some Super Searching myself, but didn't find anything definitive. But the one by blue_cowdawg as a reply to comprehensive error handling was supportive of my latter method. Thanks for pointing that one out.


      —Brad
      "The important work of moving the world forward does not wait to be done by perfect men." George Eliot
Re: Friendly error trapping
by graff (Chancellor) on Sep 13, 2005 at 01:07 UTC
    I need to put the best face on the error and keep the program going.
    You mean, if the code tries to open an output file and this generates an error instead of succeeding, you just want to tell the user something like "this probably won't work as intended..." or "no output is being saved, but we'll go through the motions anyway...", and forge ahead? Somehow that doesn't seem like the right thing to want. (Maybe I misunderstood the question.)

    IMO, a vital element in writing software for use by others is to anticipate, as much as possible and reasonable, what can go wrong during execution due to factors beyond the scope of the software -- such as "disk full" or hardware/permission issues that make it impossible to save output to a file.

    Among the things thus identified, if you can differentiate things according to severity (e.g. things that really make execution pointless/doomed vs. things that just disable some features), it's great to provide distinct and appropriate handling for each case.

    But in any case, either you have to trust your users' ability to heed and understand your error and warning messages, or else you have to set yourself up to do some hand-holding when then come back to you asking what your error and warning messages mean.

    The behavior of the code in the face of unsuitable conditions needs to be appropriate to the seriousness of the problem (not to any notion of "saving face"), but more importantly, the errors and warnings generated by the code -- and the documentation that accompanies the code -- need to be clear enough, and provide enough detail (but not a bunch of irrelevant detail), so that the user can understand both the problem and what needs to be done about it (or at least, the user can easily relay the message to you or some other support programmer who can figure it out if the user is clueless).

    If you're talking about an interactive process where you need to tell the user things like "I couldn't use that last output file name you provided because ... -- please try a different path or file name:", that's a question of providing the appropriate user interface.

    You should have an underlying model of the user(s): what they know and understand, what information they need to provide in order to make the software work, and what will be, for them, the most effective and least troublesome way to provide that information. With that, the error handling should fall into place pretty naturally.

      The question made sense.

      dieing is the right response when something occurs in code that the programmer was not expecting or hasn't got around to handling.

      On the other hand, as graff points out, when an error condition can be anticipated then testing for that error and producing an alternative response is a great thing to do.

      For example, in a commercial web app, it is conceivable that a database handle may not be obtained (high load, some tweap in operations decided to take the db offline, sunspot interference). What to do in the situation.. die and leave the user hanging? No; probably a more adequate response is a "website is busy, please return back soon!". If the webpage just died then it would be particularly unpretty and unprofessional.

      Of course, if that multiline if..elsif..elsif.. statement falls through to a final else that should be impossible, then die and die spectacularly.. the programmer needs to urgently tend to the impossible!

      My question was simply this: is there something internal that die does that is necessary to exit a script properly?

      The very point of this is to provide a more detailed error message, such as you describe, so the user does indeed know what the problem is without ungraciously dumping them in the middle of nowhere.

      Update: To clarify, almost 100% of the time, this scenario is usually part of processing an HTML form which is uploading something or performing some file op, such as deleting a file. If there is an error, I use HTML::Template and HTML::FillInForm to re-display the form with the error message at the top so they can try again (or at least know what happened).


      —Brad
      "The important work of moving the world forward does not wait to be done by perfect men." George Eliot
        This sounds like the question centers on issues of application design and having some sort of understanding of the user.

        Regarding the conditions and information that the app needs in order to do its work for the user, you need to know by design what things are provided directly and explicitly by the user (command-line args, form parameters, dialog responses, maybe the contents of data files), and what things are determined by the OS/environment/config/etc (stuff that may be outside the user's control or awareness, including the contents of some data files). It can be easier to make the user understand the problem if they caused it and you can make that clear to them; if the problem stems from something other than their direct input, it might be harder to explain, but you should still try.

        As for tying up any "internal" loose ends before exiting a script "properly" in case of a problem, this really depends on what the app is doing. If you intend to keep running (e.g. retry by taking the user back to a point just before a bad input), you need to know what steps, if any, need to be undone, what inputs need to be rewound, and so on. It's a difficult issue to discuss in general terms.

        In any case, there's a good chance that users will find ways to break your code that you never thought of. Go ahead and give them some code to run anyway. Make some mistakes just like we all do, and if any particular problems vex you, come back with those.

        UPDATE: In response to this part of your question:

        Is it "safe" or "good practice" not to die? Or is there some intrinsic value of die that I am missing by not using it?
        The intrinsic value of "die" is to acknowledge that for certain conditions, further execution is useless and futile. That's the point of using "die". This can be "contextualized" within an eval block, so that you can trap a bad condition without actually halting execution of the whole script -- that is, by putting a "die" condition inside an eval block, you're saying "further execution within this block is pointless" (but on exiting the block, the main script can still decide what needs to be done next).
Re: Friendly error trapping
by pg (Canon) on Sep 13, 2005 at 00:26 UTC
    "I know that the Perlish way to handle an errors, like writing to a file, is to die, print the error $!, and take the forced exit."

    Don't think that's the Perlish way, but rather a simple way of giving examples in ones's documentations/posts. I believe that most of the people will not die their programs like this. I don't think you need to worry about the die part too much.

Re: Friendly error trapping
by tcf03 (Deacon) on Sep 13, 2005 at 02:03 UTC
    Maybe im missing something, but couldn't you just use warn? or even carp?

    Ted
    --
    "That which we persist in doing becomes easier, not that the task itself has become easier, but that our ability to perform it has improved."
      --Ralph Waldo Emerson