12

Consider this simple class:

package Foo;
use Moose;
has foo => ( is => 'rw', isa => 'Int' );

And then this code:

use Try::Tiny;
use Foo;
my $f = try {
    Foo->new( foo => 'Not an Int' );
}
catch {
    warn $_;
};

The code dies with a nice big error message about type constraints failing.

I'd like to be able to extract what attribute failed (foo), what the reason was (failed type constraint) and what the value passed was (Not an Int) without having to parse an error string to get the info.

Something like this:

catch {
    if( $_->isa( 'MooseX::Exception::TypeConstraint' ) ) {
         my $attrib = $_->attribute;
         my $type   = $_->type;
         my $value  = $_->bad_value;

         warn "'$value' is an illegal value for '$attrib'.  It should be a $type\n"; 
    }
    else {
         warn $_;
    }
};

Is this possible? Is there a MooseX distribution that can make this happen? Better yet, is there some Moose feature that I missed that will make this possible?

Update: I am particularly interested in type constraints, but other Moose errors would be very good as well. I am also aware that I can throw objects with die. So, structuring exceptions in code I write is relatively easy.

daotoad
  • 26,689
  • 7
  • 59
  • 100

3 Answers3

4

I haven't tried it myself, but I think MooseX::Error::Exception::Class might be what you're looking for.

cjm
  • 61,471
  • 9
  • 126
  • 175
  • This is very interesting. It works like MooseX::Throwable but is built on Exception::Class and defines the beginnings of an exception class hierarchy. Internally, it parses the error message to determine what sort of exception to throw. – daotoad Feb 11 '10 at 05:46
  • Unfortunately it hasn't been updated for a while, and fails its tests pretty much everywhere. – Sam Kington Nov 04 '11 at 13:25
3

Check out MooseX::Throwable, which replaces the error_class value in the metaclass. The code looks a little old however (metaroles do support error class roles now), but the current method looks like it will still work.

Ether
  • 53,118
  • 13
  • 86
  • 159
  • This looked really promising, but the only attributes it has are: stack (the stack trace), previous_exception (in case we have nested exceptions), and message (the "Attribute (foo) does not ...."). Still stuck parsing the message. – daotoad Feb 11 '10 at 01:17
  • 1
    Aye, I suspect that someone is going to have to make a real exception class and explicitly construct it in cases of error (in the core code), rather than simply constructing a class around the raw messages that are created now. It would be quite a job to go through all the core code to change it to use these, but I'm sure lots of people will thank you! – Ether Feb 11 '10 at 01:30
  • oops, I didn't mean to volunteer. :) I was really hoping to get a nice RTFM answer. C'est la vie. – daotoad Feb 11 '10 at 01:36
  • @daotoad. Come on. You could probably even get a grant from the Perl Foundation to do it! :) – Christopher Bottoms Feb 23 '10 at 21:30
1

I had the same question about a year ago and asked at the #moose IRC channel. The answer was that Moose doesn't really support structured exceptions.... yet.

There is a general agreement that it is a shortcoming of Moose that should be fixed, but the task of introducing exceptions everywhere is tedious and hasn't (afaik) been carried out yet.

The approach in MooseX::Error::Exception::Class is very brittle, since it is based on parsing the messages from Moose.

Since you can't really get reliable structured exceptions from Moose, consider using introspection to test each of your type constraints one by one when setting a new value. Some times this is a feasible approach.

Btw: note that there is a nasty bug in the way Moose handles composite constraints.

mzedeler
  • 4,177
  • 4
  • 28
  • 41
  • Yeouch! That's one heckuva bug. While Exception::Class looks interesting, it seems **wrong** to me to use two different object building libraries in one project. Throwable is interesting, but I think exceptions are one of the places where inheritance makes sense. Anything you throw, should **be an** exception, rather than "do Throwable" (whatever that means...). I am not 100% sold that inheritance is *the* correct solution. Maybe the answer is a single exception class with appropriate attributes. I am not sure yet. – daotoad Jun 16 '11 at 05:43
  • That bug has since been closed, it would appear. – Sam Kington Jan 04 '12 at 22:08