Moose structured exceptions

0599bca0a7a5365993135af90236779d?s=47 Upasana
September 02, 2014

Moose structured exceptions

0599bca0a7a5365993135af90236779d?s=128

Upasana

September 02, 2014
Tweet

Transcript

  1. 1.

    Upasana or : How I learned to stop Worrying and

    Love structured Exceptions. Upasana August 31, 2014
  2. 2.

    About me ◮ A Perl programmer. ◮ Working at booking.com

    ◮ Contact information ◮ me@upasana.me ◮ upasana on irc.perl.org
  3. 3.

    Summer of 2013 ◮ I did ◮ Code for around

    200 Moose exception classes. ◮ Making Moose throw instances of those exception classes. ◮ Test cases & documentation for all those 200 Moose exceptions. ◮ In short, 368 changed files with 23,830 additions and 1,479 deletions. ◮ I’m not crazy! I didn’t do it for free. ◮ GNOME foundation & The Perl Foundation paid me 5000 USD for this work :).
  4. 4.

    So, I’m going to tell you a little bit about

    GNOME’s Outreach Program for Women.
  5. 5.

    GNOME’s Outreach Program for Women ◮ Helps people who identify

    as women or cis or trans to get involved in free and open source software. ◮ Tasks involve coding, testing, documentation, marketing, community management, support etc. ◮ Wikimedia, Linux Kernel, OpenStack Foundation and Mozilla are some of the regular participants (Perl participated only twice :) ). ◮ Moose structured exceptions were done via OPW, by me under mentorship of Shawn Moore and Jesse Luehrs.
  6. 6.

    Outline ◮ Types of errors : ◮ In band errors

    ◮ autodie pragma. ◮ String errors. ◮ Structured exceptions. ◮ How to handle each type of error? ◮ Various problems with different types of errors.
  7. 7.

    Outline ◮ How one type of error is better than

    the other? :D ◮ How you could define your own exception classes while working with Moose? ◮ Future of Moose Exceptions
  8. 8.

    In-band errors ◮ Functions which return output and error information

    on the same channel. ◮ Common in C and Perl. ◮ Example : 1 #!/ usr/bin/env perl 2 3 open my $out , "<", "output" or die $!; 4 print <$out >;
  9. 9.

    In-band errors ◮ Good things - ◮ They inform me

    about the errors atleast. ◮ Bad things - ◮ Errors may go unnoticed if you forget to check the return value.
  10. 10.

    Staying safe with in-band errors ◮ You could use autodie

    if you forget to check the return value.
  11. 11.

    use autodie; 1 use feature qw(switch); 2 3 eval {

    4 use autodie; 5 open(my $fh , ’<’, "xyz.txt"); 6 7 my @records = <$fh >; 8 9 # Do things with @records ... 10 11 close($fh); 12 13 }; 14 given ($@) { 15 when (undef) { print "No error" } 16 when (’open ’) { print "Error from open\n" } 17 default { print "Not an autodie error at all." } 18 }
  12. 12.

    String errors ◮ Errors which just have a string message.

    ◮ Sometimes stack trace also. ◮ Thrown using die, croak and confess. ◮ Older versions of Moose used to have string errors.
  13. 13.

    String errors example 1 { 2 package Person; 3 use

    Moose; 4 5 # name is required \& should be a String 6 has ’name ’ => ( 7 is => ’ro’, 8 isa => ’Str’, 9 required => 1, 10 ); 11 12 # age is required \& should be an Integer 13 has ’age ’ => ( 14 is => ’ro’, 15 isa => ’Int’, 16 required => 1, 17 ); 18 }
  14. 14.

    String error handling 1 use Try :: Tiny; 2 try

    3 { 4 my $person = Person ->new( 5 name => "Mr. Moose", 6 age => "xyz", 7 ); 8 } 9 catch 10 { 11 my $exception = $_; 12 if( $exception =~ /\ QAttribute (age) does not pass the type constraint because :/ ) 13 { 14 # I’m not going to parse the error message for displaying the incorrect age! 15 die "What! Your age is ....? :P"; 16 } 17 elsif( $exception =~ /\ QAttribute (age) is required/ ) 18 { 19 die "Why didn ’t you give age?"; 20 } 21 #... 22 };
  15. 15.

    Good things about string errors ◮ Error information and output

    are separate. ◮ More informative than in-band errors. ◮ Can’t go unnoticed easily.
  16. 16.

    Bad things about string errors ◮ If-else blocks ◮ If

    someone changes the error message, then your error handling code is useless. ◮ Want more error information? ◮ Use Carp::Always. ◮ Parse the error message. ◮ Have more if-else blocks. ◮ Use structured exceptions.
  17. 17.

    Structured exceptions aka exception objects ◮ Contain information about the

    error in the form of attributes (stack trace, error message etc). ◮ Java, C++ and latest version of Moose has exception objects.
  18. 18.

    Structured exceptions handling 1 { 2 package Person; 3 use

    Moose; 4 5 # name is required \& should be a String 6 has ’name ’ => ( 7 is => ’ro’, 8 isa => ’Str’, 9 required => 1, 10 ); 11 12 # age is required \& should be an Integer 13 has ’age ’ => ( 14 is => ’ro’, 15 isa => ’Int’, 16 required => 1, 17 ); 18 }
  19. 19.

    Structured exceptions handling 1 use Try :: Tiny; 2 try

    3 { 4 my $person = Person ->new( 5 name => "Mr. Moose", 6 age => "xyz", 7 ); 8 } 9 catch 10 { 11 my $exception = $_; 12 my $prefix = "Moose :: Exception"; 13 if( blessed $exception ) 14 { 15 if( $exception ->isa($prefix.":: AttributeIsRequired ") ) 16 { 17 my $attr_name = $exception -$> $attribute_name ; 18 die "Why didn ’t you give $attr_name?"; 19 } 20 elsif( $exception ->isa($prefix.":: ValidationFailedForTypeConstraint ") ) 21 { 22 my $attr_name = $exception -$>$attribute ->name; 23 my $value = $exception ->value; 24 die "What! Your $attr_name is $value? :P"; 25 } 26 } 27 };
  20. 20.

    Good things about structured exceptions ◮ Easily accessible attributes. ◮

    Explicitly verbose. ◮ Cleaner code ◮ fewer if-else blocks. ◮ No regular expression matching for error messages like string exceptions.
  21. 21.

    Good things about structured exceptions ◮ Role matching could be

    used in catch block ◮ Some exception classes does common Roles. ◮ So ->does(’Moose::Exception::Role::Class) can be used instead where you’re expecting two different exceptions which have a common Role Moose::Exception::Role::Class. ◮ Ability to improve exception messages freely ◮ Once, all the modules dependent on Moose change their code to use exception objects, we can easily improve exception messages.
  22. 22.

    Good things about structured exceptions ◮ Easier to inspect the

    stack trace for custom error handling since it’s a Devel::StackTrace object. ◮ It’s now much easier to override how Moose formats errors ◮ Now error formatting is just in one place: Moose::Exception. ◮ Previously there were calls to confess, croak, and die all over the Moose codebase. ◮ Documentation of exception types
  23. 23.

    Bad things about structured exceptions ◮ It made Moose ◮

    A bit heavy, 200 files... ◮ A bit slow, but we have tried to avoid it by loading specific classes at runtime. ◮ You need to create a new file for every new exception. ◮ Polluted MetaCPAN search results, because of 200 exception classes, but it can be solved. ◮ Perl’s built in exceptions are strings, and everybody is already used to them.
  24. 25.

    Throwable ◮ a Moo::Role that provides mechanism for building exception

    classes. ◮ provides a throw method. ◮ comes with Throwable::Error, which is a basic error class ◮ adds stack trace handling, one-arg constructor, stringification
  25. 26.

    Throwable 1 package MyApp :: Error; 2 use Moose; 3

    with ’Throwable ’; 4 use overload ’""’ => sub { shift ->message }; 5 6 has message => ( 7 is => ’ro’, 8 isa => ’Str’, 9 required => 1, 10 ); 11 # ... 12 MyApp ::Error ->throw(message => "Invalid argument");
  26. 27.

    Future plans of Moose ◮ Modifying some cool exception messages

    like: ◮ ”Cannot have an isa option and a does option if the isa does not do the does on attribute (”.$self->attribute name.”)”; ◮ Factoring out common behaviour among exception classes and making roles for them. ◮ Making user-defined exceptions work with Moose. ◮ As of now, Moose::Util::throw exception works with Moose::Exception::* ◮ But it should also work with exceptions having different namespace. ◮ Structured exceptions were the first, very tedious step toward improving Moose’s error formatting
  27. 28.

    Future plans of Moose Exceptions ◮ As of now, stack

    trace looks like: 1 Attribute (age) is required at lib/Moose/Exception.pm line 32 2 Moose :: Exception :: _build_trace (’Moose :: Exception :: AttributeIsRequired =HA 3 SH(0 x208b760)’) called at reader Moose :: Exception :: trace (defined at 4 lib/Moose/Exception.pm line 6) line 7 5 ... 6 eval {...} at 7 /home/upasana/perl5/perlbrew/perls/perl -5.18.0/ lib/site_perl /5.18.0/ Try/ 8 Tiny.pm line 74 9 Try:: Tiny ::try(’CODE (0 x1effca0)’, ’Try:: Tiny :: Catch=REF(0 x208b940)’) 10 called at /home/upasana/Test/Perl/ test_two_errors .pl line 54 ◮ Useful information is at the bottom of the stack trace. ◮ We can make it better by playing with Carp level, though it’s a bit complex. ◮ Carp::Clan and may be some other modules could be of some help in this.
  28. 29.

    For more information about structured exceptions in Moose ◮ perldoc

    Moose::Manual::Exceptions::Manifest ◮ perldoc Moose::Manual::Exceptions ◮ Shawn’s blog: http://sartak.org/2013/10/structured-exceptions-in-moos ◮ https://metacpan.org/module/Throwable ◮ https://metacpan.org/pod/Try::Tiny
  29. 30.

    Credits ◮ John SJ Anderson - I stole some exception

    handling code from his talk. ◮ Shawn Moore and Chris Prather - For reviewing this talk. ◮ Tobias Oetiker - For suggesting me to add in-band errors. ◮ Yuval Kogman - I stole some disadvantages of structured exceptions from his blog : http://blog.woobling.org/2010/07/are-we-ready-to-ditch- ◮ #moose-dev on irc.perl.org - For helping me with some of structured exceptions code. ◮ For in-band errors - https://www.securecoding.cert.org/confluence/display/se ◮ For autodie : https://metacpan.org/pod/autodie ◮ Inspiration behind the title of this talk - Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb