This is part of The Pile, a partial archive of some open source mailing lists and newsgroups.
To: modperl@apache.org From: Tatsuhiko Miyagawa <miyagawa@edge.co.jp> Subject: RFC: Exception::Handler Date: Fri, 11 Jan 2002 22:07:57 +0900 Seeing through Dave Rolsky's Exception::Class and Sig::PackageScoped has let me make the following module, called Exception::Handler. In fact I rarely use $SIG{__DIE__} for exception handling, but the concept of the module would be a bit interesting. Especially eval { }; if ($@->isa('FooException')) { # ... } elsif ($@->isa('BarException')) { # ... } else { # ... } code like this can be greatly simplified. Any suggestions welcome, escpecially from gurus of exception, Matt and Dave ;) See t/*.t for typical usage. http://bulknews.net/lib/archives/Exception-Handler-0.01.tar.gz NAME Exception::Handler - Hierarchical exception handling SYNOPSIS use Exception::Class 'MyException', 'AnotherException' => { isa => 'MyException' }, 'YetAnotherException' => { isa => 'AnotherException' }, 'FooBarException'; use Exception::Handler MyException => \&my_handler, AnotherException => \&another_handler, __DEFAULT__ => \&default_handler; eval { MyException->throw }; # my_handler() eval { AnotherException->throw; }; # another_handler() eval { YetAnotherException->throw; }; # another_handler() : hierarchical eval { FooBarException->throw; }; # default_handler() sub my_handler { my $exception = shift; # ... } sub another_handler { } sub default_handler { } DESCRIPTION Exception::Handler allows you to handle exception with various subs each of which registered for an appropriate class of exception. This module can nicely work with Dave Rolsky's Exception::Class and Grahamm Barr's Error module. TODO * Lexical handler, which may be done via "local". AUTHOR Tatsuhiko Miyagawa <miyagawa@bulknews.net> This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. SEE ALSO Exception::Class, Sig::PackageScoped === To: "Tatsuhiko Miyagawa" <miyagawa@edge.co.jp>, <modperl@apache.org> From: "Jay Lawrence" <Jay@Lawrence.Net> Subject: Re: Exception::Handler Date: Fri, 11 Jan 2002 17:39:33 -0500 For what it is worth - I would encourage you to check out the Error package as well. Rather than: eval { }; if ($@->isa('FooException')) { # ... } elsif ($@->isa('BarException')) { # ... } else { # ... } You would have: try { code; } catch FooException with { code for FooExceptions; } catch BarException with { code for BarExceptions; } otherwise { }; And you can throw exceptions with details on the nature of the exception: throw FooException ( -text => "You foo'ed at line bar", -value => $line ); and in the try block: try { do foo; } catch FooException with { my $exception=shift; print "Uh oh, we have a problem with foo: " . $exception->text; }; === To: Jay Lawrence <Jay@Lawrence.Net> From: Dave Rolsky <autarch@urth.org> Subject: Re: Exception::Handler Date: Fri, 11 Jan 2002 17:34:30 -0600 (CST) On Fri, 11 Jan 2002, Jay Lawrence wrote: > For what it is worth - I would encourage you to check out the Error package > as well. > > Rather than: > > eval { }; > if ($@->isa('FooException')) { > # ... > } elsif ($@->isa('BarException')) { > # ... > } else { > # ... > } > > You would have: > try { > code; > } catch FooException with { > code for FooExceptions; > } catch BarException with { > code for BarExceptions; > } otherwise { > }; And the fun potential for memory leaks with nested closures. > And you can throw exceptions with details on the nature of the exception: > > throw FooException ( -text => "You foo'ed at line bar", -value => > $line ); You can do that without using Error.pm's try/catch stuff by simply using Error's exception objects or the Exception::Class provided exception objects. AFAICT, Tatsuhiko's module is designed to work with either of those types of objects transparently, but it provides an alternate mechanism for catching exceptions. And anything inspired by my Sig::PackageScoped module scares me, but its an interesting idea ;) === To: Tatsuhiko Miyagawa <miyagawa@edge.co.jp> From: Matt Sergeant <matt@sergeant.org> Subject: Re: RFC: Exception::Handler Date: Sat, 12 Jan 2002 07:52:13 +0000 (GMT) On Fri, 11 Jan 2002, Tatsuhiko Miyagawa wrote: > use Exception::Handler > MyException => \&my_handler, > AnotherException => \&another_handler, > __DEFAULT__ => \&default_handler; > > eval { MyException->throw }; # my_handler() > eval { AnotherException->throw; }; # another_handler() > eval { YetAnotherException->throw; }; # another_handler() : hierarchical > eval { FooBarException->throw; }; # default_handler() I don't like this for the same reason I don't like $SIG{__DIE__} - it promotes action at a distance. In a 1000 line .pm file I *want* to have my exception catching mechanism next to my eval{} block. === To: "Jay Lawrence" <Jay@Lawrence.Net> From: Tatsuhiko Miyagawa <miyagawa@edge.co.jp> Subject: Re: Exception::Handler Date: Sat, 12 Jan 2002 18:33:59 +0900 On Fri, 11 Jan 2002 17:39:33 -0500 "Jay Lawrence" <Jay@Lawrence.Net> wrote: > For what it is worth - I would encourage you to check out the Error package > as well. Exactly, in fact the module can nicely work with Error.pm. See t/*.t for details ;) === To: Dave Rolsky <autarch@urth.org> From: Tatsuhiko Miyagawa <miyagawa@edge.co.jp> Subject: Re: Exception::Handler Date: Sat, 12 Jan 2002 18:42:58 +0900 On Fri, 11 Jan 2002 17:34:30 -0600 (CST) Dave Rolsky <autarch@urth.org> wrote: > > You would have: > > try { > > code; > > } catch FooException with { > > code for FooExceptions; > > } catch BarException with { > > code for BarExceptions; > > } otherwise { > > }; > > And the fun potential for memory leaks with nested closures. Matt has an idea for doing this with Filter module, instead of nasty closures. > AFAICT, Tatsuhiko's module is designed to work with either of those types > of objects transparently, but it provides an alternate mechanism for > catching exceptions. Absolutely. > And anything inspired by my Sig::PackageScoped module scares me, Yep. the module is greaty inspired, and in fact borrows its some code from Sig::PackageScoped! > but its an interesting idea ;) === To: Tatsuhiko Miyagawa <miyagawa@edge.co.jp> From: Matt Sergeant <matt@sergeant.org> Subject: Re: Exception::Handler Date: Sat, 12 Jan 2002 10:25:23 +0000 (GMT) On Sat, 12 Jan 2002, Tatsuhiko Miyagawa wrote: > On Fri, 11 Jan 2002 17:34:30 -0600 (CST) > Dave Rolsky <autarch@urth.org> wrote: > > > > You would have: > > > try { > > > code; > > > } catch FooException with { > > > code for FooExceptions; > > > } catch BarException with { > > > code for BarExceptions; > > > } otherwise { > > > }; > > > > And the fun potential for memory leaks with nested closures. > > Matt has an idea for doing this with Filter module, instead of > nasty closures. Actually unfortunately I even had code, but it was on my laptop that died. I may resurrect the project in time for this year's Perl Conference, provided Tony Blair decides to instigate my vision of a 30 hour day. === To: Matt Sergeant <matt@sergeant.org> From: Tatsuhiko Miyagawa <miyagawa@edge.co.jp> Subject: Re: Exception::Handler Date: Sat, 12 Jan 2002 19:29:16 +0900 On Sat, 12 Jan 2002 10:25:23 +0000 (GMT) Matt Sergeant <matt@sergeant.org> wrote: > > > > Matt has an idea for doing this with Filter module, instead of > > nasty closures. > > Actually unfortunately I even had code, but it was on my laptop that died. Sad. > I may resurrect the project in time for this year's Perl Conference, > provided Tony Blair decides to instigate my vision of a 30 hour day. AFAIK Filter module can't work with eval EXPR code, thus making Apache::Registry unhappy. === To: modperl@apache.org From: Rob Nagler <nagler@bivio.biz> Subject: Re: RFC: Exception::Handler Date: Sat, 12 Jan 2002 10:24:42 -0700 Matt Sergeant writes: > I don't like this for the same reason I don't like $SIG{__DIE__} - it > promotes action at a distance. In a 1000 line .pm file I *want* to have my > exception catching mechanism next to my eval{} block. You need this flexibility, but Perl allows you to do more, for good reasons. One of the things I don't like about traditional try/catch handling is that it doesn't allow for class level programming. You need to allow any subroutine to try/catch exceptions (die). It's also nice to notify any object in the stack that there is an unhandled exception passing through its code. This eliminates a lot of explicit try/catches. This allows reuse without clutter. If you're familiar with Aspects, it's basically the same concept. === To: modperl@apache.org From: Dominique Quatravaux <dom@idealx.com> Subject: Re: RFC: Exception::Handler Date: Mon, 14 Jan 2002 09:55:50 +0100 > One of the things I don't like about traditional try/catch handling is > that it doesn't allow for class level programming. You need to allow > any subroutine to try/catch exceptions (die). It's also nice to > notify any object in the stack that there is an unhandled exception > passing through its code. I'm afraid I don't get it - isn't it what the "finally" functionality in Error.pm (CPAN) does ? try { stuffThatMayThrow(); } finally { releaseResources(); }; > This eliminates a lot of explicit > try/catches. Well, destructors are of some help too in that issue. (not lighting up a flamewar, just trying to understand the issues - I don't know much about Aspects, but I find exception handling with Error.pm a breeze, even for big projects) === To: modperl@apache.org From: Rob Nagler <nagler@bivio.biz> Subject: Re: RFC: Exception::Handler Date: Mon, 14 Jan 2002 08:16:57 -0700 > I'm afraid I don't get it - isn't it what the "finally" functionality > in Error.pm (CPAN) does ? > > try { > stuffThatMayThrow(); > } finally { > releaseResources(); > }; One reason for exceptions is to separate error handling code from the normal control flow. This makes the normal control flow easier to read. If releaseResources() is to be called whenever an exception occurs, then it is advantageous to eliminate the extra syntax in the class's methods and just have releaseResources() called whenever an exception occurs and the object is on the stack. Our exception handling class searches down the stack looking for objects which implement handle_die(). It then calls $object->handle_die($die), where $die is the exception instance. This increases the cost and complexity of exception handling, while decreasing the cost and complexity of normal control flow. It also ensures that whenever the object is involved in an exception, handle_die() is called giving it an opportunity to examine the exception and clean up global state if necessary. > > This eliminates a lot of explicit > > try/catches. > > Well, destructors are of some help too in that issue. Not if the object is a class or if the object is still live, e.g. the request context. We don't do a lot of instance creation/destruction in our code. For example, our Task instances are created at start up. They are executed repeatedly. Tasks decide whether to commit/rollback on every execution, independent of the path through the Task class. I'm agree with the need for try/catch. That's often the best way to handle exceptions. There are cases where a global view is need, however. Like Aspects, it ensures that you don't forget or have to put in code where it is absolutely needed. === To: Rob Nagler <nagler@bivio.biz> From: Matt Sergeant <matt@sergeant.org> Subject: Re: RFC: Exception::Handler Date: Mon, 14 Jan 2002 15:20:32 +0000 (GMT) On Mon, 14 Jan 2002, Rob Nagler wrote: > > I'm afraid I don't get it - isn't it what the "finally" functionality > > in Error.pm (CPAN) does ? > > > > try { > > stuffThatMayThrow(); > > } finally { > > releaseResources(); > > }; > > One reason for exceptions is to separate error handling code from the > normal control flow. This makes the normal control flow easier to > read. If releaseResources() is to be called whenever an exception > occurs, then it is advantageous to eliminate the extra syntax in the > class's methods and just have releaseResources() called whenever an > exception occurs and the object is on the stack. > > Our exception handling class searches down the stack looking for > objects which implement handle_die(). It then calls > $object->handle_die($die), where $die is the exception instance. This > increases the cost and complexity of exception handling, while > decreasing the cost and complexity of normal control flow. It also > ensures that whenever the object is involved in an exception, > handle_die() is called giving it an opportunity to examine the > exception and clean up global state if necessary. Might be a fun thing to try out using the mysterious PROPOGATE method (try it - implement a PROPOGATE method in your exception class, and watch for when it gets called). ===