Re: [RFC] Exceptions addition for the guide.
On Sat, 8 Apr 2000, Autarch wrote: On Sat, 8 Apr 2000, Matt Sergeant wrote: I've written a short document on exception handling for the guide, even though it's not particularly mod_perl specific, Stas thinks it would be a good addition. Take a look at it, and let me know if there is anything you would change before it's added: http://modperl.sergeant.org/guide/exceptions.html This is a good tutorial. You might want to take a look at some exception code I wrote (ftp://ftp.urth.org/pub/, grab the Exception and StackTrace tar balls) that lets you declare all your exception types via 'use' statements. I think its a bit cleaner than the AUTOLOAD method you propose as it can catch typos later on. Plus it lets you create actual class hierarchies for your exceptions, which could be nice if you want to create exception classes that do more stuff and then inherit from them. Right, the intention isn't to provide the perfect exceptions system, but to give enough of a grounding in 5.005+ exception handling to build on. I'll add a bunch of URL's (for Error, Try and Exception modules) to a SEE ALSO section at the end. -- Matt/ Fastnet Software Ltd. High Performance Web Specialists Providing mod_perl, XML, Sybase and Oracle solutions Email for training and consultancy availability. http://sergeant.org http://xml.sergeant.org
[RFC] Exceptions addition to the guide
This is the 2nd attempt, at Stas' request I'm pasting the whole thing here so you can reply and/or edit. =head1 Exception Handling for mod_perl Provided here are some guidelines for Sclean(er) exception handling for mod_perl usage, although the technique presented here applies to all of your perl programming. The reasoning behind this document is the current broken status of C$SIG{__DIE__} in the perl core - see both the perl5-porters and mod_perl mailing list archives for details on this discussion. =head1 Trapping Exceptions in Perl To trap an exception in Perl we use the Ceval{} construct. Many people initially make the mistake that this is the same as the Ceval EXPR construct, which compiles and executes code at run time, but that's not the case. Ceval{} compiles at compile time, just like the rest of your code, and has next to zero run-time penalty. When in an eval block, if the code executing die()'s for some reason, rather than terminating your code, the exception is Icaught and the program is allowed to examine that exception and make decisions based on it. The full construct looks like this: eval { # Some code here }; # Note important semi-colon there if ($@) # $@ contains the exception that was thrown { # Do something with the exception } else # optional { # No exception was thrown } Most of the time when you see these exception handlers there is no else block, because it tends to be OK if the code didn't throw an exception. =head1 Alternative Exception Handling Techniques An often suggested method for handling global exceptions in mod_perl, and other perl programs in general, is a B__DIE__ handler, which can be setup by either assigning a function name as a string to C$SIG{__DIE__} (not particularly recommended) or assigning a code-ref to C$SIG{__DIE__}, the usual way of doing so is to use an anonymous sub: $SIG{__DIE__} = sub { print "Eek - we died with:\n", $_[0]; }; The current problem with this is that C$SIG{__DIE__} is a global setting in your script, so while you can potentially hide away your exceptions in some external module, the execution of C$SIG{__DIE__} is fairly magical, and interferes not just with your code, but with all code in every module you import. Beyond the magic involved, C$SIG{__DIE__} actually interferes with perl's normal exception handling mechanism, the Ceval{} construct. Witness: $SIG{__DIE__} = sub { print "handler\n"; }; eval { print "In eval\n"; die "Failed for some reason\n"; }; if ($@) { print "Caught exception: $@"; } The code unfortunately prints out: In eval handler Which isn't quite what you would expect, especially if that C$SIG{__DIE__} handler is hidden away deep in some other module that you didn't know about. There are work arounds however. One is to localise C$SIG{__DIE__} in every exception trap you write: eval { local $SIG{__DIE__}; ... }; Obviously this just doesn't scale - you don't want to be doing that for every exception trap in your code, and it's a slow down. A second work around is to check in your handler if you are trying to catch this exception: $SIG{__DIE__} = sub { die $_[0] if $^S; print "handler\n"; }; However this won't work under Apache::Registry - you're always in an eval block there! My personal solution is to warn people about this danger of C$SIG{__DIE__} and inform them of better ways to code. This is my attempt at that. =head1 Better Exception Handling The Ceval{} construct in itself is a fairly weak way to handle exceptions as strings. There's no way to pass more information in your exception, so you have to handle your exception in more than one place - at the location the error occured, in order to construct a sensible error message, and again in your exception handler to deconstruct that string into something meaningful (unless of course all you want your exception handler to do is dump the error to the browser). A little known fact about exceptions in perl 5.005 is that you can call die with an object. The exception handler receives that object in $@. This is how I always handle exceptions now, as it provides an extremely flexible and scaleable exceptions solution. =head2 A Little Housekeeping First though, before we delve into the details, a little housekeeping is in order. Most, if not all, mod_perl programs consist of a main routine that is entered, and then dispatches itself to a routine depending on the parameters passed and/or the form values. In a normal C program this is your main() function, in a mod_perl handler this is your handler() function/method. In order for you to be able to use exception handling to it's best extent you need to change your script to have some sort of global exception
Re: [RFC] Exceptions addition to the guide
On Sun, 9 Apr 2000, Matt Sergeant wrote: For similar exception handling techniques, see the Try module, the Exception module and the Error module, all on CPAN. There is no Exception module on CPAN? If you're referring to my code, it's not yet on CPAN because I don't think I can justify attempting to take that namespace especially in light of the fact there eventually will probably be exceptions in Perl itself. If you're referring to Peter Seibel's Exceptions module, that module is totally non-functional with modern Perl and has been superseded by Graham Barr's Error module. LError - Graham Barr's excellent OO try/catch/finally module. LExceptions - Another exceptions module. LTry - Tony Olekshy's. Adds an unwind stack. Not on CPAN (yet?). See my above comment about the Exceptions module. I wouldn't mind being mentioned here. You could link to the FTP site I mentioned before (ftp.urth.org/pub). Eventually I may come up with a suitable name and put it on CPAN. -dave /*== www.urth.org We await the New Sun ==*/
[RFC] Exceptions addition for the guide.
I've written a short document on exception handling for the guide, even though it's not particularly mod_perl specific, Stas thinks it would be a good addition. Take a look at it, and let me know if there is anything you would change before it's added: http://modperl.sergeant.org/guide/exceptions.html -- Matt/ Fastnet Software Ltd. High Performance Web Specialists Providing mod_perl, XML, Sybase and Oracle solutions Email for training and consultancy availability. http://sergeant.org http://xml.sergeant.org
Re: [RFC] Exceptions addition for the guide.
On Sat, 8 Apr 2000, Matt Sergeant wrote: I've written a short document on exception handling for the guide, even though it's not particularly mod_perl specific, Stas thinks it would be a good addition. Take a look at it, and let me know if there is anything you would change before it's added: http://modperl.sergeant.org/guide/exceptions.html This is a good tutorial. You might want to take a look at some exception code I wrote (ftp://ftp.urth.org/pub/, grab the Exception and StackTrace tar balls) that lets you declare all your exception types via 'use' statements. I think its a bit cleaner than the AUTOLOAD method you propose as it can catch typos later on. Plus it lets you create actual class hierarchies for your exceptions, which could be nice if you want to create exception classes that do more stuff and then inherit from them. -dave /*== www.urth.org We await the New Sun ==*/
Re: [RFC] Exceptions addition for the guide.
Also, checkout Graham Barr's Error.pm for an OO styled "try, throw, catch" model. Really nice for a complete OO Perl design, IMHO. --Jeff The one I use is a customized version but it's basically the OO "try, throw, catch" model that I've seen in other languages. On Sat, 8 Apr 2000, Autarch wrote: N; charset=US-ASCII X-Spam-Rating: locus.apache.org 1.6.2 0/1000/N Status: U On Sat, 8 Apr 2000, Matt Sergeant wrote: I've written a short document on exception handling for the guide, even though it's not particularly mod_perl specific, Stas thinks it would be a good addition. Take a look at it, and let me know if there is anything you would change before it's added: http://modperl.sergeant.org/guide/exceptions.html This is a good tutorial. You might want to take a look at some exception code I wrote (ftp://ftp.urth.org/pub/, grab the Exception and StackTrace tar balls) that lets you declare all your exception types via 'use' statements. I think its a bit cleaner than the AUTOLOAD method you propose as it can catch typos later on. Plus it lets you create actual class hierarchies for your exceptions, which could be nice if you want to create exception classes that do more stuff and then inherit from them. -dave 0