Can the Perl compiler tell me if I have an unchecked exception in my code?
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?)
Two potential answers. Pick whichever you like better:
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.
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 mightdie
. 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.
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/
Have you checked CPAN? Error::TryCatch is one option, Exception::Class is another, etc. etc.
Also, see Object Oriented Exception Handling in Perl.
from document "Exceptions"
$@ doesn't tell us where the error occurred
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"
精彩评论