Skip Menu |
 

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the Exception-Class-TryCatch CPAN distribution.

Report information
The Basics
Id: 43759
Status: resolved
Priority: 0/
Queue: Exception-Class-TryCatch

People
Owner: Nobody in particular
Requestors: QKoch [...] web.de
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: Questions about TryCatch's philosophy
Date: Sun, 01 Mar 2009 19:36:44 +0100
To: bug-Exception-Class-TryCatch [...] rt.cpan.org
From: Oliver Koch <QKoch [...] web.de>
Download smime.p7s
application/x-pkcs7-signature 5.4k

Message body not shown because it is not plain text.

use 5.8.8; use strict; use Data::Dumper 2.121; use Exception::Class 1.26 ( 'Ex::TestExceptionClass', 'Ex::TestExceptionClass::Test1' => { isa => 'Ex::TestExceptionClass' }, 'Ex::TestExceptionClass::Test2' => { isa => 'Ex::TestExceptionClass' }, 'Ex::TestExceptionClass::Test2Sub' => { isa => 'Ex::TestExceptionClass' }, 'Ex::TestExceptionClass::Test3' => { isa => 'Ex::TestExceptionClass' }, 'Ex::TestExceptionClass::Test3::Ex1' => { isa => 'Ex::TestExceptionClass::Test3' }, 'Ex::TestExceptionClass::Test3::Ex2' => { isa => 'Ex::TestExceptionClass::Test3' }, 'Ex::TestExceptionClass::Test3::Ex3' => { isa => 'Ex::TestExceptionClass::Test3' } ); use Exception::Class::TryCatch 1.12; # Declare prototypes. sub Test1(); sub Test2Sub(); sub Test2(); sub Test3(); sub ExitProgram($); print "$0 started.\n"; select STDERR; $| = 1; # make unbuffered select STDOUT; $| = 1; # make unbuffered # Initialize global variables. my $TestNr = 0; # **************** $TestNr++; print("$TestNr.) Simple try/throw/catch.\n"); print "\$@ = $@\n"; try eval { throw Ex::TestExceptionClass 'Ex::TestExceptionClass thrown!'; }; print "\$@ = $@\n"; if(catch my $Ex) { print("Caught ", ref($Ex), "\n"); print($Ex->message, "\n"); } print "\$@ = $@\n"; if(catch my $Ex) { print("Caught ", ref($Ex), "\n"); print("I would expect, that no exception was caught!\n"); print("Is exception still on stack?\n"); $@ = ""; } else { print("No exception on stack.\n"); } print "\$@ = $@\n"; if(catch my $Ex) { print("Caught ", ref($Ex), "\n"); print("Is exception still on stack?\n"); } else { print("No, but \$@ must be reset, too.\n"); } # **************** $TestNr++; print("\n"); print("$TestNr.) Simple try/catch without throw.\n"); print "\$@ = $@\n"; try eval { die("Just a simple die."); }; print "\$@ = $@\n"; if(catch my $Ex) { print("Caught ", ref($Ex), "\n"); print($Ex->message, "\n"); if($Ex->isa('Exception::Class::Base')) { print("Why is a die() of class 'Exception::Class::Base'?\n"); print("I would expect something like 'Exception::Die'!\n"); } else { print("Something unexpected happened (maybe a die).\n"); } } print "\$@ = $@\n"; if(catch my $Ex) { print("Caught ", ref($Ex), "\n"); print("I would expect, that no exception was caught!\n"); print("Is exception still on stack?\n"); $@ = ""; } else { print("No exception on stack.\n"); } print "\$@ = $@\n"; if(catch my $Ex) { print("Caught ", ref($Ex), "\n"); print("Is exception still on stack?\n"); } else { print("No, but \$@ must be reset, too.\n"); } # **************** $TestNr++; print("\n"); print("$TestNr.) throw in a subroutine caught outside.\n"); print "\$@ = $@\n"; Test1(); print "\$@ = $@\n"; if(catch my $Ex) { print("Caught ", ref($Ex), "\n"); if($Ex->isa('Ex::TestExceptionClass::Test1')) { print($Ex->message, "\n"); } else { print("Unexpected exception!\n"); } } $@ = ""; # **************** $TestNr++; print("\n"); print("$TestNr.) throw and rethrow in subroutines caught outside, if not caught inside.\n"); print "\$@ = $@\n"; try eval { Test2(); }; print "\$@ = $@\n"; if(catch my $Ex) { print("Caught ", ref($Ex), "\n"); if($Ex->isa('Ex::TestExceptionClass::Test2')) { print($Ex->message, "\n"); } else { print("Unknown exception!\n"); print($Ex->message, "\n"); } } else { print("No further exceptions.\n"); } $@ = ""; # **************** $TestNr++; print("\n"); print("$TestNr.) 3 throws and a die in a subroutine, stack cleaned up outside.\n"); print "\$@ = $@\n"; Test3(); print "\$@ = $@\n"; if(catch my $Ex) { # I miss a simple boolean function indicating, try eval { $Ex->rethrow() }; # that's something on the exception stack! $@ = ""; # Required to avoid endless loop. while (catch my $Ex){ print("Caught ", ref($Ex), "\n"); if($Ex->isa('Ex::TestExceptionClass::Test3')) { print($Ex->message, "\n"); } else { print("Unexpected exception!\n"); print($Ex->message, "\n"); } } ExitProgram(-4); } ExitProgram(0); sub Test1 () { print "Test1: \$@ = $@\n"; try eval { throw Ex::TestExceptionClass::Test1 'Ex::TestExceptionClass::Test1 thrown!'; }; print "Test1: \$@ = $@\n"; } sub Test2Sub () { print "Test2Sub: \$@ = $@\n"; #try eval { throw Ex::TestExceptionClass::Test2Sub 'Ex::TestExceptionClass::Test2Sub thrown!'; #}; print "Test2Sub: \$@ = $@\n"; } sub Test2 () { print "Test2: \$@ = $@\n"; try eval { Test2Sub(); print "Test2: \$@ = $@\n"; throw Ex::TestExceptionClass::Test2 'Ex::TestExceptionClass::Test2 thrown!'; }; print "Test2: \$@ = $@\n"; if(catch my $Ex) { print("Caught ", ref($Ex), "\n"); if($Ex->isa('Ex::TestExceptionClass::Test2')) { print($Ex->message, "\n"); } else { print("Unexpected exception!\n"); print($Ex->message, "\n"); $Ex->rethrow(); } } print "Test2: \$@ = $@\n"; } sub Test3 () { print "Test3: \$@ = $@\n"; try eval { throw Ex::TestExceptionClass::Test3::Ex1 'Ex::TestExceptionClass::Test3::Ex1 thrown!'; }; print "Test3: \$@ = $@\n"; try eval { throw Ex::TestExceptionClass::Test3::Ex2 'Ex::TestExceptionClass::Test3::Ex2 thrown!'; }; print "Test3: \$@ = $@\n"; try eval { die "Died for some reason!"; }; print "Test3: \$@ = $@\n"; try eval { throw Ex::TestExceptionClass::Test3::Ex3 'Ex::TestExceptionClass::Test3::Ex3 thrown!'; }; print "Test3: \$@ = $@\n"; } sub ExitProgram ($) { my $ExitCode = shift; if($ExitCode == 0) { print "$0 finished successfully."; } else { print "$0 finished with exit code $ExitCode."; } exit($ExitCode); } __END__;
Download (untitled) / with headers
text/plain 2.9k
Dear David, At first: Many thanks for your excellent extension to Exception::Class. However, I have a few questions about TryCatch's philosophy. I added a perl script to demonstrate, how I intend to use TryCatch module. But some of my ideas doesn't seem to be fully compatible with TryCatch's philosophy. Example 1: According documentation: "The exception is either popped from a hidden error stack (see try) or, if the stack is empty, taken from the current value of $@." My confusion starts after catch() caught (and popped) the thrown exception from the error stack. The copy of this exception is still in $@ and the next catch() catches the same 'exception' again. The next point is, that $@ isn't "popped" from this "error stack". *From this example I would expect, that the content of $@ is ignored by catch(), because it's just a copy of the exception on the error stack. * Example 2: This example is the same as the example above, but a simple die is used instead of a throw(). Again $@ isn't "cleaned" by catch(), so I have to do this manually, to avoid a repeated catch of the same message. But it's difficult to decide, whether $@ must be reset or not, because I can't notice whether it caught an exception or a $@ entry. Even from the exception class (Exception::Class::Base) it can't be concluded for sure, what was the source of the caught exception. *I suggest to change the class of "$@ exceptions" to something unique like "Exception::Unexpected::Die" (if "thrown" by a die).* *As a consequence from example 1 and 2 I feel, that the approach to use the error stack AND $@ for catch(), leads easily to confusing situations. I think, it would be clearer, that catch() ignores $@ and try() pushes $@ entries to the error stack as every other exceptions with a special exception class. * Example 3: This example shows, that I possibly throw an exception in a subroutine, that is processed outside the subroutine. Works fine! Example 4: This example shows how an "unexpected" exception is passed upwardly, if it couldn't be handled inside the subroutine. Works fine! Note: If you uncomment the try eval {} in Test2Sub(), I expected to catch the first exception from Test2Sub() in the main part. But it seems to be gone. *Where is it?* Example 5: In this example a couple of exceptions are thrown in a subroutine, that should be handled outside all at once. (One possible idea is to clean up the error stack at program end and exit with an error code.) *Here I miss something to avoid the "if(catch) - try eval { rethrow } - while(catch)" construct. I suggest - according to "scalar(@error_stack)" - a function like "ExceptionsOnStack()". This would allow a simpler approach like "while(ExceptionsOnStack()) { ... }".* To conclude, I want to confirm again, that TryCatch module is very useful for me and - please - my remarks shouldn't be taken as a critique! Maybe, I have the wrong view on how the module should be used. So, I would be really thankful for clarification. Many thanks in advance and kind regards, Oliver
It's a little hard to follow exactly what you're trying to achieve. So I've quickly skimmed your code and will give you my snap reaction. Let me know if that helps. If not, maybe you could elaborate with more specifics on how you're trying to handle errors and I'll see if I can help figure out if TryCatch is right for you. I think that the main issue is that you're mixing usage of try/catch and $@. The philosophy of TryCatch is that once you start using it, you need to forget about $@ entirely. Think about how a normal "eval {}" works. At the end of the eval, $@ is guaranteed to be either an exception or the empty string. (Side note -- the exception could be from an eval {} in the DESTROY from an object that went out of scope at the end of the original eval; this is viewed by many to be either a perl bug or a class design bug having eval in DESTROY.) So "try eval {}" is just "try( eval {} )" so immediately after eval {}, the result is passed to try. At that precise moment, when $@ is either an exception or the empty string, the value in $@ is pushed onto a stack. Then later, when you want to know the result of that *specific* eval, you call catch() to pop the value off the stack. In between try() and catch(), anything could happen and thus $@ may or may not be related to the original eval. One other thing that occurs to me is that I think I assume that try/catch will happen in the same scope. That's not strictly necessary, but since you need to pair one (and only one) catch with each try, I'd worry trying to guarantee that if you're calling try() in a sub and catching it the calling sub. In one of the examples, you're calling try(), try(), try() before doing any catching. That's something you're explicitly warned not to do. See the documentation about try() that starts "try must always be properly bracketed with a matching catch". Another side note -- die becomes an Exception::Class::Base because I don't want to try to define an exception hierarchy. What if something else defined Exception::Die? The only thing I know is safe is Exception::Class::Base. Does any of that clarify? -- David
Subject: Re: [rt.cpan.org #43759] Questions about TryCatch's philosophy
Date: Mon, 02 Mar 2009 23:14:11 +0100
To: bug-Exception-Class-TryCatch [...] rt.cpan.org
From: Oliver Koch <QKoch [...] web.de>
Download (untitled) / with headers
text/plain 5.4k
Dear David, many thanks for your prompt and substantial answer. David Golden via RT schrieb: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=43759 > > > It's a little hard to follow exactly what you're trying to achieve. So > I've quickly skimmed your code and will give you my snap reaction. Let > me know if that helps. If not, maybe you could elaborate with more > specifics on how you're trying to handle errors and I'll see if I can > help figure out if TryCatch is right for you. >
To clarify this a little bit and explain it in a few words: My basic approach to exception handling is to use exceptions for error handling, not only for exceptional situations. A subroutine should pass back their result value. If an error occurs, it should be dealt with by an exception. Show quoted text
> I think that the main issue is that you're mixing usage of try/catch and > $@. The philosophy of TryCatch is that once you start using it, you > need to forget about $@ entirely. > > Think about how a normal "eval {}" works. At the end of the eval, $@ is > guaranteed to be either an exception or the empty string. (Side note -- > the exception could be from an eval {} in the DESTROY from an object > that went out of scope at the end of the original eval; this is viewed > by many to be either a perl bug or a class design bug having eval in > DESTROY.) > > So "try eval {}" is just "try( eval {} )" so immediately after eval {}, > the result is passed to try. At that precise moment, when $@ is either > an exception or the empty string, the value in $@ is pushed onto a stack. > > Then later, when you want to know the result of that *specific* eval, > you call catch() to pop the value off the stack. In between try() and > catch(), anything could happen and thus $@ may or may not be related to > the original eval. > >
The first two examples were just for me to learn how TryCatch works internally. So, it's clear to me, that I used too many catches for the number of tries according your documentation. All you've said above is logically and holds perfectly as long as I combine every try() with exactly one catch(). However, I can't really see, why catch() uses $@ (if the stack is empty). If it is guaranteed, that the content of $@ is pushed onto the stack and the stack is empty now, then for sure there was a catch() before popping the exception from the stack. So every exception was caught (= every error handled). From this point of view it makes no sense to catch the same (old) exception again (and again and again) from $@. Show quoted text
> One other thing that occurs to me is that I think I assume that > try/catch will happen in the same scope. That's not strictly necessary, > but since you need to pair one (and only one) catch with each try, I'd > worry trying to guarantee that if you're calling try() in a sub and > catching it the calling sub. >
From my understanding of other exception-throwing languages like C++ or Java, it's usual to throw an exception, that is caught elsewhere outside the subroutine (maybe some levels higher). And this approach makes sense for me in Perl, too, so I'm very happy, that TryCatch implemented such an exception stack. Show quoted text
> In one of the examples, you're calling try(), try(), try() before doing > any catching. That's something you're explicitly warned not to do. See > the documentation about try() that starts "try must always be properly > bracketed with a matching catch". > >
And I think, I did not so. Coming back to my first paragraph, my approach is, that I don't want to miss any error/exception, that was raised in the program. But it could be, that I don't how to handle the exception properly. So, I want to make sure, that at least every raised exception is reported to the user (and every try() gets its matching catch()). This is done in the while loop after Test3(). And I assume, this is what you denoted in your documentation: try eval { Exception::Class::Base->throw('error') }; do { # cleanup that might use "try/catch" again }; catch my $err; # catches a matching "try" I think, my Test3() + while(catch()) does more or less the same. To conclude the above: From my point of view the exception stack is exactly, what I'm looking for, but I think the stack should behave like any other stack in Perl. If I pop something from @Array and @Array is empty, then I get undef and not the content from e. g. $_ instead. Show quoted text
> Another side note -- die becomes an Exception::Class::Base because I > don't want to try to define an exception hierarchy. What if something > else defined Exception::Die? The only thing I know is safe is > Exception::Class::Base. > >
I see your point and it's a reasonable conservative approach. On the other hand, I think, by "reducing" the class to Exception::Class::Base, information gets lost about the source of the exception. Wouldn't it make sense to introduce one (or maybe a few) special sub-class(es) to Exception::Class::Base indicating the source of this non-throw() exception(s)? Especially, because I'm not able to define this sub-class on my own for e. g. a die(). (I'm not sure, whether it's technically possible to conclude from $@ after an eval {}, what wrote into $@.) Show quoted text
> Does any of that clarify? > > -- David > >
Yes and no. I'm still not sure, whether I miss (or misunderstood) something. I hope, I could make clearer, what my approach is and would be glad, if we could finally find a common understanding. Regards, Oliver
Subject: Re: [rt.cpan.org #43759] Questions about TryCatch's philosophy
Date: Mon, 2 Mar 2009 18:31:08 -0500
To: bug-Exception-Class-TryCatch [...] rt.cpan.org
From: David Golden <dagolden [...] cpan.org>
Download (untitled) / with headers
text/plain 2.5k
On Mon, Mar 2, 2009 at 5:39 PM, Oliver Koch via RT <bug-Exception-Class-> Show quoted text
> However, I can't really see, why catch() uses $@ (if the stack is > empty). If it is guaranteed, that the content of $@ is pushed onto the > stack and the stack is empty now, then for sure there was a catch() > before popping the exception from the stack. So every exception was > caught (= every error handled). From this point of view it makes no > sense to catch the same (old) exception again (and again and again) from $@.
It's not very consistent, I admit. It was originally intended to support catch without needing try -- for the simplest case when someone just wants to eval {} and have any error promoted to an Exception::Class object. Perhaps I can add some sort of switch that gives the stricter behavior you're looking for. Show quoted text
>> One other thing that occurs to me is that I think I assume that >> try/catch will happen in the same scope.  That's not strictly necessary, >> but since you need to pair one (and only one) catch with each try, I'd >> worry trying to guarantee that if you're calling try() in a sub and >> catching it the calling sub. >>
>  From my understanding of other exception-throwing languages like C++ or > Java, it's usual to throw an exception, that is caught elsewhere outside > the subroutine (maybe some levels higher).
I'm not talking about *throwing* an exception and catching it higher. I'm talking about wrapping something in an eval and then checking for the error higher. It makes perfect sense to do this: try eval { sub_that_throws_exception() }; catch my $error; It *doesn't* make sense to do this: sub_that_might_use_try_eval(); catch my $error; You should be catching errors where you eval. Show quoted text
> On the other hand, I think, by "reducing" the class to > Exception::Class::Base, information gets lost about the source of the > exception. > Wouldn't it make sense to introduce one (or maybe a few) special > sub-class(es) to Exception::Class::Base indicating the source of this > non-throw() exception(s)? > Especially, because I'm not able to define this sub-class on my own for > e. g. a die().
That's a fair point. I suppose you could override $SIG{__DIE__} to throw whatever exception you want, but that could break anything *else* that uses $SIG{__DIE__}. Perhaps I can add a way for a user to specify an Exception::Class they want TryCatch to use for die instead of Base. You've raised two good interface ideas. I'm putting them into my 'todo' for TryCatch. No promises on when I'll get a chance to implement them, though. Feel free to ask me again in a couple weeks if I haven't gotten around to it. -- David
Subject: Re: [rt.cpan.org #43759] Questions about TryCatch's philosophy
Date: Tue, 03 Mar 2009 21:13:28 +0100
To: bug-Exception-Class-TryCatch [...] rt.cpan.org
From: Oliver Koch <QKoch [...] web.de>
Download (untitled) / with headers
text/plain 2.5k
David Golden via RT schrieb: Show quoted text
> <URL: http://rt.cpan.org/Ticket/Display.html?id=43759 > > > It's not very consistent, I admit. It was originally intended to > support catch without needing try -- for the simplest case when > someone just wants to eval {} and have any error promoted to an > Exception::Class object. >
From this point of view it makes perfectly sense to use $@. Show quoted text
> Perhaps I can add some sort of switch that gives the stricter behavior > you're looking for. >
Both approaches (eval-catch and try eval-catch) are somehow contradictory and a switch seems to me an appropriate solution. Show quoted text
> I'm not talking about *throwing* an exception and catching it higher. > I'm talking about wrapping something in an eval and then checking for > the error higher. > > It makes perfect sense to do this: > > try eval { sub_that_throws_exception() }; > catch my $error; > > It *doesn't* make sense to do this: > > sub_that_might_use_try_eval(); > catch my $error; > > You should be catching errors where you eval. >
I think, I see your point, but I'm not sure, that I can agree. I assume, that the above "catch my error;" are "if(catch my $error) { some error handling }". At first it shouldn't matter, whether the try eval-block is in- or outside a subroutine. (But your point is a reliable 1:1 match between try and catch.) Second: What happens, if the eval block exits with no error? I expect, that in this case "catch my $error" should return false or undef and the if-branch isn't executed (and $error should be undef). From this point of view even the second example makes sense. Can you follow this perspective? Show quoted text
> That's a fair point. I suppose you could override $SIG{__DIE__} to > throw whatever exception you want, but that could break anything > *else* that uses $SIG{__DIE__}. Perhaps I can add a way for a user to > specify an Exception::Class they want TryCatch to use for die instead > of Base. >
We are on common ground, that overriding $SIG{__DIE__} is rather dangerous. And I feel, that I'm not expert enough to overview all consequences, when including this into a complex perl program. But you're idea sounds to me as the perfect solution. The user of TryCatch should know, what class is the right for these non-throw exceptions. Show quoted text
> You've raised two good interface ideas. I'm putting them into my > 'todo' for TryCatch. No promises on when I'll get a chance to > implement them, though. Feel free to ask me again in a couple weeks > if I haven't gotten around to it. >
I'm looking forward to it. Thanks. Regards, Oliver
Subject: Re: [rt.cpan.org #43759] Questions about TryCatch's philosophy
Date: Tue, 3 Mar 2009 17:36:09 -0500
To: bug-Exception-Class-TryCatch [...] rt.cpan.org
From: David Golden <dagolden [...] cpan.org>
Download (untitled) / with headers
text/plain 2.2k
On Tue, Mar 3, 2009 at 3:13 PM, Oliver Koch via RT <bug-Exception-Class-TryCatch@rt.cpan.org> wrote: Show quoted text
>> It makes perfect sense to do this: >> >> try eval { sub_that_throws_exception() }; >> catch my $error; >> >> It *doesn't* make sense to do this: >> >> sub_that_might_use_try_eval(); >> catch my $error; >> >> You should be catching errors where you eval. >>
> I think, I see your point, but I'm not sure, that I can agree. > I assume, that the above "catch my error;" are "if(catch my $error) { > some error handling }".
Yes. Show quoted text
> At first it shouldn't matter, whether the try eval-block is in- or > outside a subroutine. (But your point is a reliable 1:1 match between > try and catch.) > Second: What happens, if the eval block exits with no error? I expect, > that in this case "catch my $error" should return false or undef and the > if-branch isn't executed (and $error should be undef). >  From this point of view even the second example makes sense. > Can you follow this perspective?
Technically, I agree. But in practice, I think you should have try() and catch() in the same scope. Why? Because it indicates the granularity of what you care about. For example: try eval { # stuff sub_that_throws_exception(); # stuff } if ( catch my $err ) { ... } This makes it clear what you want to catch. The only reason that I could see to do it differently is if you want to silently accumulate all exceptions *without stopping execution* and then process/log all exceptions afterwards: stuff_that_uses_try_eval(); while (my $err = catch ) { # assuming I fix catch to do this properly # handle each $err } So if I fix catch, yes, you *can* do that, but I wouldn't consider it good style. I think it could be hard for someone who didn't write the code to follow it. Compare to this: my @error_log; sub stuff_that_uses_try_eval { # stuff try eval { # dangerous stuff }; catch my $err and push @error_log, $err; # continue } stuff_that_uses_try_eval(); for my $err ( @error_log ) { # handle each $err } That makes it explicit at the point you call eval{} exactly what happens with an exception -- in this case, it's pushed to a global error log array. You could just as easily record the error in other ways. -- David
Subject: Re: [rt.cpan.org #43759] Questions about TryCatch's philosophy
Date: Wed, 04 Mar 2009 22:30:37 +0100
To: bug-Exception-Class-TryCatch [...] rt.cpan.org
From: Oliver Koch <QKoch [...] web.de>
Download (untitled) / with headers
text/plain 3.7k
Dear David, David Golden via RT schrieb: Show quoted text
> <URL: http://rt.cpan.org/Ticket/Display.html?id=43759 > >
>> At first it shouldn't matter, whether the try eval-block is in- or >> outside a subroutine. (But your point is a reliable 1:1 match between >> try and catch.) >> Second: What happens, if the eval block exits with no error? I expect, >> that in this case "catch my $error" should return false or undef and the >> if-branch isn't executed (and $error should be undef). >> From this point of view even the second example makes sense. >> Can you follow this perspective? >>
> > Technically, I agree. But in practice, I think you should have try() > and catch() in the same scope. Why? Because it indicates the > granularity of what you care about. > > For example: > > try eval { > # stuff > sub_that_throws_exception(); > # stuff > } > if ( catch my $err ) { ... } > > This makes it clear what you want to catch. >
I agree. Show quoted text
> The only reason that I could see to do it differently is if you want > to silently accumulate all exceptions *without stopping execution* and > then process/log all exceptions afterwards: > > stuff_that_uses_try_eval(); > while (my $err = catch ) { # assuming I fix catch to do this properly > # handle each $err > } >
Indeed, this was with some respect my intention: From my survey in the web exception handling seems to have some philosophical aspect. There are developers, who use exceptions to handle something, that is really exceptional (like a divide by 0). This seems to be an enhancement compared to old programs, that just crashed in such situations. In the other corner you find developers, who treat exception handling as an additional channel (next to the normal return value of a function) for passing back errors. In between you might find any possible grade of opinion. (It seems, that I tend to the latter fraction.) However, let's come back to the point. I want to be sure, that I report all exceptions to the user. And I can't always guarantee, that every exception is handled in the place where it happens. My program should look like this: sub do_b_might_throw_ex { do_d_might_throw_ex_but_cant_handle; try eval { do_e_might_throw_ex; } if(catch my $ex) { if($ex->isa("e") { cure_error_e; } else { $ex->rethrow; } } do_f; } try eval { do_a_might_throw_ex_but_cant_handle; try eval { do_b_might_throw_ex; } if(catch my $ex) { if($ex->isa("b") { cure_error_b; } else { $ex->rethrow; } } do_c; } clean_up; while(catch my $ex) { print $ex->error; exit(-1); } So, if I really think it over, I realize, that the while loop at the end is somehow paranoiac. An if should perfectly do it. Nevertheless, I'm still convinced of this approach (after changing the while to an if). The big advantage is from my point of view, that I don't have to pollute the code with exit()s or die()s, if I don't know to handle the problem. (Although it is very common to let a perl script die whenever something strange happens, I don't like this in complex programs.) From my approach there's one central place, where unknown exceptions are handled and cleaning up is done. I think, this is good style, too. I agree, that throwing three exceptions before handling it (as shown in my first e-mail), isn't a good idea. I think, we could discuss endless and both of us can find many sensible reasons ... However, from my point of view, the discussion was very valuable and helpful. I'm happy, if you consider to implement the $@-switch, that brings more clarity in the usage of TryCatch. The user-defined class(es) for die etc. would be nice, too, for a more appropriate error handling. I'm looking forward to an implementation. Many thanks again for the helpful discussion. Regards, Oliver
Download (untitled) / with headers
text/plain 128b
Marking this 5 year old ticket resolved as there's nothing to do about it. Try::Tiny has largely superceded this module anyway.


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

Please report any issues with rt.cpan.org to rt-cpan-admin@bestpractical.com.