Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you best attribute errors in a Perl method to the caller

Given a method that may fail with warnings and/or errors, I want the error method to show up at the caller. Fir instance this script:

foo(0);         # line 1

sub foo {
    1 / shift;  # line 4
}

Produces the error Illegal division by zero at foo.pl line 4, but I want Illegal division by zero at foo.pl line 1. There should be several ways if I put the method in a module or if I wrap the method body in eval, but I have not found an easy way like this:

sub foo {
    attributeErrorsToCaller; # do some magic
    1 / shift;
}

Is there such a way?


EDIT: mirod's answer comes close not what I was looking for:

Foo::foo(0);         # line 1

package Foo;
use diagnostics -traceonly;
BEGIN { disable diagnostics; }

sub foo {
    enable diagnostics;
    1 / shift;       # line 9
}

Without enable diagnostics the error message is Illegal division by zero at foo.pl line 9.. With enable diagnostics it is still too verbose, but this may also be useful:

Uncaught exception from user code:
    Illegal division by zero at foo.pl line 10.
 at foo.pl line 10
     Foo::foo(0) called at foo.pl line 2

I bet I could hack diagnostics to get exactely the feature I want, but using diagnostics as raw module is probably more recommended.

like image 259
Jakob Avatar asked Jun 14 '11 06:06

Jakob


2 Answers

Carp is very, very close to "do_some_magic" you are asking for. For instance:

#!/usr/bin/perl -w 
use strict;

# I fork to be as close to natural die() as possible. 
fork() or Foo::foo();
fork() or Foo::bar();
fork() or Foo::baz();
sleep 1;

package Foo;
use Carp; 

sub foo { die "Some error (foo)"; }; 
sub bar { croak "Some error (bar)"; }; 
sub baz { bar(); };

As you can see, croak() acts almost like die(), but reports error to the caller (even indirectly -- see baz).

However, it won't handle 1/0 for you -- either use eval (or even Try::Tiny), or check input values* and say "division by zero" yourself.

Carp is standard, which means understandable by further maintainers of your code, and also can print neat stack traces via confess or cluck or even print Carp::longmess (see the doc).

*which is good anyway

like image 96
Dallaylaen Avatar answered Sep 24 '22 06:09

Dallaylaen


Would use diagnostics; be enough for you? It will dump the call stack, so the caller is quite easy to find out.

For example in you example:

#!/usr/bin/perl

use strict;
use warnings;
use diagnostics;


foo(0);

sub foo
  { 
    return 1/$_[0];
  }

gives this:

`Illegal division by zero at test_die line 12 (#1)
    (F) You tried to divide a number by 0.  Either something was wrong in
    your logic, or you need to put a conditional in to guard against
    meaningless input.

Uncaught exception from user code:
        Illegal division by zero at test_die line 12.
 at test_die line 12
        main::foo(0) called at test_die line 8
like image 37
mirod Avatar answered Sep 22 '22 06:09

mirod