in reply to Dealing with errors in subroutines

In my humble opinion it is a good idea to throw an exception when an error occurred. The caller is then free to either catch the exception (with eval BLOCK) and work with $@, or to not catch it have the error abort the program, printing out the error message.

For example you could do something along these lines:

for (@users) { my $success = eval { add_account($_); }; warn "Can't add user '$_': $@" unless $success; }

This has the advantage over a plain return() that throwing the exception works the same if you call subs from add_account() and they detect an error.

Perl 6 - links to (nearly) everything that is Perl 6.

Replies are listed 'Best First'.
Re^2: Dealing with errors in subroutines
by Bloodnok (Vicar) on Sep 09, 2009 at 12:17 UTC
    I agree.

    Moreover, the handling of thrown exceptions is far more scaleable if something like Exception::Class is used in favour of parsing fatal error strings - the likeliehood of breaking client code is far greater when the client code parses the error string than when the client code attempts to catch a known class of exception i.e. the interface is greatly simplified, which as outcomes go, is highly desirable.

    To my mind, the use of Error solely for the, slightly distasteful, syntactic sugar is a moot point : the intending user has to compare (for themselves) the benefit of tidier code with the drawback of a non-returning return in the try/catch blocks (as by perrin et al in this thread) - a well understood drawback that can be mitigated for by the simple expedient of a specific case (pun intended) in the coding standards coupled with code review and good unit test cases. The memory leakage problem, as noted in the above link, appears to have now been fixed.

    A user level that continues to overstate my experience :-))
Re^2: Dealing with errors in subroutines
by Boldra (Curate) on Sep 14, 2009 at 07:57 UTC
    Somewhere along the way I picked up the habit of writing this idiom so:
    for (@users) { my $success = eval { add_account($_); }; if($@ or not $success) { warn "Can't add user '$_': $@" }
    But I don't remember why I thought it might be better. Certainly not from readability! What do others think of this kind of double-checking?


    - Boldra
      It's not paranoid but good practice, because (as ELISHEVA pointed out below) a DESTROY method can accidentally reset the global $@ variable, as this small piece of code demonstrates:
      use strict; use warnings; use Data::Dumper; sub DESTROY { eval { 1 } } eval { my $obj = bless {}; die "wrong"; }; print Dumper $@; __END__ $VAR1 = '';

      The correct solution is to localize $@ in the DESTROY sub, but you can't always rely on third-party modules to do such things correctly.

      Perl 6 - links to (nearly) everything that is Perl 6.