Re: Use of "die" in OO modules
by brian_d_foy (Abbot) on Jan 18, 2007 at 19:09 UTC
|
People have their various opinions about this, and I'm generally against dying in a module only because most of Perl doesn't do that. I want to be consistent in my error handling rather than introducing a new way with every module I use.
The modules I find that annoy me, however, are the ones that die for the wrong reasons. Sometimes I don't care if the call failed, but it shouldn't stop my program if it does. That's a lot different than not being able to connect to a database or open a necessary file, where I probably do want to think about what's going on and how to recover from it.
So, that's not really an answer. If you are going to do that sort of thing, though, use Carp's croak instead. That way the filename and line number in the error message come from the place it was called insted of inside the module, which isn't very helpful.
I have a chapter on "Detecting and Reporting Errors" for Mastering Perl. Despite my personal bias I try to present both sides fairly. :)
| [reply] [d/l] |
Re: Use of "die" in OO modules
by imp (Priest) on Jan 18, 2007 at 19:17 UTC
|
Code should fail as early as possible to avoid collateral damage, and to help identify the source of a problem.
Using special return values will clutter the code with assertions, which decreases readability and increases the chance that you will miss an exceptional condition.
It is also difficult to come up with a consistent failure convention. Using undef is a bad idea as it is true in list context (any value is), and some functions will return undef as a valid response. -1 is less appropriate. You could bless an error object and return that, but that strikes me as an ugly solution.
I prefer to use Exception::Class, or if I am feeling lazy then die will do. Perl Best Practices has an excellent chapter on Error Handling (13) - I highly recommend it. | [reply] |
|
Thanks for your input, though I should have specified one thing more clearly: when I said I return (undef), I meant that I just return;, I don't return undef;. I'm aware of the problem with returning undef explicitly. (For the unaware: a bare return gives the caller an undef, regardless of whether the call was in scalar or list context. Returning an explicit undef gives the caller undef in scalar context and a list containing one element (undef) in list context.)
| [reply] [d/l] [select] |
Re: Use of "die" in OO modules
by kyle (Abbot) on Jan 18, 2007 at 19:14 UTC
|
I like to use Exception::Class to throw exceptions. If the caller wants to ignore my gravely important problems, it will have to do that explicitly. It's nice to have a module that contains all the exceptions I'll want to throw. It looks like:
package My::Exceptions;
use Exception::Class
(
'My::Bad' =>
{ description => 'Way bad', },
'My::OtherBad' =>
{ description => 'Bad as well',
isa => 'My::Bad', },
);
1;
Then anywhere I need them, just use My::Exceptions and My::Bad->throw( error => 'Woe is me' ). | [reply] [d/l] [select] |
Re: Use of "die" in OO modules
by jettero (Monsignor) on Jan 18, 2007 at 19:03 UTC
|
I tend to use various methods from Carp when I'm building OO things. I can die places my module is broken and croak places where the caller did it wrong. There are a lot of choices in Carp, but I think croak is probably what you need.
I figure the caller can always eval { $object->something } if they need to.
UPDATE: The more I think about it though, I really only die (croak) when arguments passed differ unusuably from the documentation.
| [reply] [d/l] |
Re: Use of "die" in OO modules
by perrin (Chancellor) on Jan 18, 2007 at 21:05 UTC
|
Here are the rules I use:
- Never use return codes to indicate failure. People will forget to check them and you will have silent failures. It's happened to me too many times.
- If I want to be able to tell which thing failed, I use Exception::Class objects. You can compare them with $@->isa('Foo'). That's much easier than trying to parse error messages to see which thing died.
- If the error is not something I can handle and continue on, i.e. I just want to log it and send a friendly error page to the user, I just use Carp::croak(). Nearly all unexpected errors (like a failed database connection) are like this.
| [reply] |
|
And I second the idea of not using a return code to signify what failed; I do however condone letting undef indicate that there is an error (that can be inspected some other, appropriate, way) if there's no potential for undef as a valid data return.
| [reply] |
|
Uh, undef is a return code. I don't think that's any better than saying "79" indicates a failure.
| [reply] |
|
|
Re: Use of "die" in OO modules
by gaal (Parson) on Jan 18, 2007 at 20:02 UTC
|
In Perl 6, you as a library author have the option of not taking sides! The fail throws an exception or returns undef (but sets $! with the unthrown exception), at the caller's discretion. See here for a longer writeup.
$HOLY_WARS-- | [reply] [d/l] [select] |
Re: Use of "die" in OO modules
by bart (Canon) on Jan 19, 2007 at 12:01 UTC
|
DBI lets the user of the module decide, through the attribute/parameter RaiseError when you connect. I think DBI is a large and widely enough used module, to count as a good, well tested example. And it appears to work well, to me. | [reply] |
|
I recently added a ErrStr var to my modules, kinda of like the DBI::errstr. So if the object constructor fails the object is an undef and the the Errstr can be checked, i.e.
my $obj = Some::Module->new() or die $Some::Module::Errstr, $/;
...otherwise if there is an error with a method call the error string can be retrieved,
$obj->get_errstr();
I really struggled with what was the correct way to handle the errors, I'm still not sure I like my solution.
| [reply] [d/l] [select] |
|
DBI is a module with a very wide audience. So there may be a reason why to support the behaviour of RaiseError = 0. But I with newly developed in house module I don't see any.
I'm going crazy (and rude) when I see my colleagues to write their code like this:
my $dbh = DBI->connect($data_source, $username, $password, \%attr) or
+die $DBI::errstr;
...
my $sth = $dbh->prepare(...) or die $DBI::errstr;
Why rude? Because
- There is usually (always) nothing to do if the DBI method fails but die. So why to bother with return value and clutter you code with unnecessary die
- If there would be something to do (probability 0.001%) writing the eval block is as easy as checking the value returned.
And why they write their scripts this way? Because they saw it in DBI perldoc.
This should be probably a topic of a new meditation but that is how the whole Perl works. You start with "There is more than one way how to do it" and then you will need the very clever (no irony) "Perl Best Practices" book to tell you that all the ways but one are wrong.
| [reply] [d/l] |
Re: Use of "die" in OO modules
by adrianh (Chancellor) on Jan 19, 2007 at 12:24 UTC
|
You can put me in the "use exceptions (plus Exception::Class if you need to return more than just 'an error happened'" camp.
My reasons for this still match the ones I wrote at Re^2: Best Practices for Exception Handling.
| [reply] |
|
Thanks for the link - interesting reading. The whole raison d'etre for my original post was that though I philosophically fall into the same camp, I have problems with the implementation/execution - in the absence of true built-in Exception handling, I have to decide between a couple of options: either fake up a try/catch type of thing by using eval {...}; if($@){...} or go with the old return undefined and let the caller inspect the object's error() method.
| [reply] [d/l] |
|
| [reply] |
|
|
|