Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Moose structured exceptions

Avatar for Upasana Upasana
September 02, 2014

Moose structured exceptions

Avatar for Upasana

Upasana

September 02, 2014
Tweet

More Decks by Upasana

Other Decks in Programming

Transcript

  1. Upasana or : How I learned to stop Worrying and

    Love structured Exceptions. Upasana August 31, 2014
  2. About me ◮ A Perl programmer. ◮ Working at booking.com

    ◮ Contact information ◮ [email protected] ◮ upasana on irc.perl.org
  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. So, I’m going to tell you a little bit about

    GNOME’s Outreach Program for Women.
  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. 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. 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. 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. 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. Staying safe with in-band errors ◮ You could use autodie

    if you forget to check the return value.
  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. 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. 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. 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. Good things about string errors ◮ Error information and output

    are separate. ◮ More informative than in-band errors. ◮ Can’t go unnoticed easily.
  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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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