views:

126

answers:

4

Is there a way in Perl to declare that a method can throw an error (or die)?

EDIT: What interests me the most is a way to get the compiler or IDE to tell me I have an unchecked exception somewhere in my code.

I always loved how in Java, a method could handle an Exception and/or throw it. The method signature allows to put "throws MyException", so a good IDE/compiler would know that if you use said method somewhere in your code, you'd have to check for the Exception or declare your function to "throws" the Exception further.

I'm unable to find something alike in Perl. A collegue of mine wrote a method which "dies" on incorrect input, but I forget to eval-if($@) it... offcourse the error was only discovered while a user was running the application.

(offcourse I doubt if there is any existing IDE that could find these kind of things for Perl, but atleast perl -cw should be able to, no?)

A: 

from document "Exceptions"

  1. $@ doesn't tell us where the error occurred

  2. We can get around this with a custom function:

    sub throw { my $mess = join('', @_); $mess =~ s/\n?$/\n/; my $i = 1; local $" = "', '"; package DB; while (my @parts = caller($i++)) { my $q; $q = "'" if @DB::args; $mess .= " -> $parts3" . " at $parts1 line $parts2\n"; } die $mess; }

With that you can also take references from "CPAN" and "Object Oriented Exception Handling in Perl"

Space
Please Please please, add comment for downvote. I want to know what i misunderstood.
Space
I'm not the downvoter, but I suspect that the reason you got downvoted is that the OP asked "how can I determine whether a given method's defined set of behaviors includes the possibility that it might throw an exception" and your answer does not address this question.
Dave Sherohman
Thanks Dave, really appreciate your response.
Space
I didn't downvote ya, but I did edit my question to steer future reponses into the "detect uncatched exceptions" way. Maybe ask the editor?
Konerak
A: 

Have you checked CPAN? Error::TryCatch is one option, Exception::Class is another, etc. etc.

Also, see Object Oriented Exception Handling in Perl.

Pedro Silva
Thank you. Yes, I've checked CPAN and the Error/Exception thingies (therefor the tags on my question), but I was looking for a way to get the compiler/IDE to tell me I have an unchecked exception somewhere in my code (so at compiletime, not at runtime). I can't seem to find that on the pages you mentioned (but maybe I'm looing over it, in which case: could you point me in more detail?)
Konerak
@Konerak: "unchecked" exceptions are not evil. Sometimes what you need to do is die, and there's no automatic reason why that needs to be caught.
Ether
+3  A: 

Two potential answers. Pick whichever you like better:

  1. In Perl, this is indicated by the module's POD. There's no way of marking it programmatically, so you need to rely on the documentation instead.

  2. Any method can die, or at least any nontrivial method. It's going to call something else, which probably calls something else, etc., so the only way to guarantee that no exception will be thrown is to trace down through all the levels of (potential) calls to verify that there's nothing there that might die. Much more pragmatic to just assume that exceptions are always a possibility and code accordingly.

Edited to add: As a general rule, Perl5 and static code analysis don't really get along all that well. My understanding is that this is one of the motivations behind the language redesign in Perl6, so you may have better luck there.

Dave Sherohman
Thanks for confirming there is no (non-trivial) programmatical way of marking it. I was thinking of annotations or something along the lines, but your last sentence in 2. offers a better practice, IMHO - one can't start annotating each existin library.
Konerak
+2  A: 

Not seen anything like this but perhaps subroutine attributes may get your part of the way?

Here is a small proof of concept using Attribute::Handlers

ThrowsExceptionHandler.pm

package ThrowsExceptionHandler;
use Modern::Perl;
use Attribute::Handlers;

our @subs;

sub ThrowsException :ATTR(CODE) {
    push @subs, {
        package  => $_[0],
        symbol   => $_[1],
        subname  => *{$_[1]}{NAME},
        referent => $_[2],
        attr     => $_[3],
        data     => $_[4],
        phase    => $_[5],
        filename => $_[6],
        linenum  => $_[7],
    };
}

sub does_throw {
    my ($class, $subname) = @_;
    (grep { $_->{subname} eq $subname } @subs) ? 1 : 0;
}

1;

example.pl

use Modern::Perl;
use base qw(ThrowsExceptionHandler);

sub baz :ThrowsException {
    die "Throws error";
}

sub foo {
    warn "warning only";
}


say ThrowsExceptionHandler->does_throw( 'baz' );  # => 1
say ThrowsExceptionHandler->does_throw( 'foo' );  # => 0

Perhaps (a mixture of) PPI, Perl::Critic and/or Padre can be adapted to use something like this?

/I3az/

draegtun
Good idea, but uuugh. Attribute::Handlers. :) And I say that as the guy with the most recent release of said module in his CPAN directory.
tsee