Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Use of "die" in OO modules

by theguvnor (Chaplain)
on Jan 18, 2007 at 18:58 UTC ( [id://595313]=perlquestion: print w/replies, xml ) Need Help??

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

I'm writing some in-house modules that will never see the light of CPAN, but still would like opinions:

What are your preferences for handling errors within your OO modules? I usually just die when starting development, but switch over to setting an error attribute in the object and returning (undef)... the philosophy being that the caller (me) should have the freedom to hang himself if he declines to check return codes. This seems to be the way most of the modules on CPAN handle things, but I know some modules just die and trust that the caller will wrap methods in an eval {} if he really wants to trap errors/exceptions.

Opinions?

Update I should also clarify that I'm talking about failures in OO methods... so calling something like $message->save_to_db() would, the way I'm currently doing things, return undef on an error and the caller can inspect $message->error to find out why. What I really want is built-in Exceptions (this is about the only thing I like better about PHP over Perl) so I'm keen on what gaal promises about Perl 6 (please hurry, p6p!).

[Jon]

Replies are listed 'Best First'.
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. :)

    --
    brian d foy <brian@stonehenge.com>
    Subscribe to The Perl Review
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.

      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.)

      [Jon]

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' ).

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.

    -Paul

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.

      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.

      [Jon]

        Uh, undef is a return code. I don't think that's any better than saying "79" indicates a failure.
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--

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.
      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.

      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

      1. 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
      2. 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.

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.

      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.

      [Jon]

        in the absence of true built-in Exception handling

        I'm curious, since I've heard others saying this, why you think Perl's exception handling isn't "true" or "built-in"?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://595313]
Approved by ikegami
Front-paged by brian_d_foy
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (3)
As of 2024-04-18 22:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found