Re: RFC 80 (v1): Exception objects and classes for builtins
On Thu, Aug 10, 2000 at 05:11:17PM +0100, Graham Barr wrote: I was more thinking of eval { # fragile code } else {# catch ALL exceptions switch ($@) { case __-isa('IO') { ... } case __-isa('Socket') { ... } else { ... } } } continue { # code always executed (ie finally) } I like it. BTW, that switch could be written like this: switch ($@-isa(^_)) { case 'IO' { ... } case 'Socket' { ... } ... # else code } -Scott -- Jonathan Scott Duff [EMAIL PROTECTED]
Re: RFC 80 (v1): Exception objects and classes for builtins
Redirected to perl6-language-flow. At 12:23 PM 8/11/00 +0100, Graham Barr wrote: On Thu, Aug 10, 2000 at 07:30:53PM -0700, Peter Scott wrote: If we're really talking about new keywords, we wouldn't need a ; at the end of the last block; it's only needed at the moment because eval is a function, not a keyword. I would vote for the keywords only because people are going to forget the ; otherwise. That maybe a reason to use `try' instead of `eval'. Another difference would be that try will rethrow uncaught error, eval does not. And of course a die in any catch block would throw an error to a try/eval block up the stack, after running the continue block. So adie; in the catch block would rethrow the same error. If we did use 'try', would we retire the block form of 'eval'? It could be confusing to have a keyword with almost identical but subtly different semantics to a function. -- Peter Scott Pacific Systems Design Technologies
Re: RFC 80 (v1): Exception objects and classes for builtins
I've moved this from perl6-language to perl6-language-flow. Tony Olekshy wrote: With the approach proposed in RFC 88 (Structured Exception Handling Mechanism), you could write that as: try { } catch { switch ($_[0]-name) { case IO { ... } case Socket { ... } } } Graham Barr wrote: the error are objects, so you need to allow for inheritance. I was just trying to point out that RFC 88 uses try {} catch {} instead of try {} otherwise {}, and that the current error comes into the catch block via @_ (as in RFC 63), so one doesn't need a "global". Sometimes you want to collect all the catching into one clause (if, say, there was lots of common code and little varying code). In other cases, you want a seperate clause for each exception (if, say, there is little common code, then the seperate clauses handle the switch for you, which is more DWIM). That's why RFC 88 allows you any combination of these operations, as in: try { } except isa = "Foo" = catch { ... } except isa = "Bar" = catch { ... } except else = catch { ... } Again, the differences between this and RFC 63's approach are, in this case, only syntactic. Yours, c, Tony Olekshy
Re: RFC 80 (v1): Exception objects and classes for builtins
I've moved this from perl6-language to perl6-language-flow. Graham Barr wrote: eval { # fragile code } else { # catch ALL exceptions switch ($@) { case __-isa('IO') { ... } case __-isa('Socket') { ... } else { ... } } } continue { # code always executed (ie finally) } Chaim Frenkel wrote: Nice. Hmm. The eval was commented to indicate fragile code, which is implied if the keyword try is used. The else was commented to indicate a catch, instead of saying catch, and the continue was commented to indicate a finally, instead of saying finally. There does seem to me to be some benefit to the clarity of the RFC 88 approach, which supports both: try { } except isa = 'IO' = catch { } except isa = 'Socket' = catch { } except else= catch { } finally { } and: try { } catch { switch ($_[0]) { case __-isa('IO') { ... } case __-isa('Socket') { ... } else { ... } } } finally { } Yours, c, Tony Olekshy
Re: RFC 80 (v1): Exception objects and classes for builtins
On Fri, Aug 11, 2000 at 09:36:32AM -0700, Peter Scott wrote: Redirected to perl6-language-flow. At 10:39 AM 8/11/00 -0400, John Porter wrote: Piers Cawley wrote: The (continue|always|finally|whatever) clause will *always* be executed, even if one of the catch clauses does a die, so you can use this to roll back the database transaction or whatever else was going on and restore any invariants. Which makes me think that it would be nice if the continue block could come before the catch block(s): establish_invariants(); try { something_risky(); } continue { restore_invariants(); } catch { handle_error_assuming_invariants_restored(); } The only point of using the continue block as you suggest is if there are multiple catch blocks, otherwise you'd just do Hm, my understanding is that the continue block would be run it there was an error or not. So with no errors you do execute try execute continue but if there was an error execute try - die execute continue execute catch Graham.
Re: RFC 80 (v1): Exception objects and classes for builtins
Peter Scott wrote: John Porter wrote: Which makes me think that it would be nice if the continue block could come before the catch block(s). I get where you're going with this but it breaks the paradigm too much. Now you need a 'finally' block again. Sometimes you want before, sometimes after, as in: try { open(*F, "foo") or throw "Can't open foo."; print F ...; } finally { close F or throw "Can't close foo."; } unwind { attempt_to_log_error_message($_[0]); } which can also be written as: try { try { open(*F, "foo") or throw "Can't open foo."; print F ...; } finally { close F or throw "Can't close foo."; } } catch { attempt_to_log_error_message($_[0]); throw; } The exception handling mechanism considered in RFC 88 has both pre-finally and post-finally exception trapping clauses, named catch and unwind. The basic syntax considered in RFC 88 is: try { ... throw ... } # try clause except TEST = catch { ... }# 0 or more catch { ... } # 0 or more finally { ... } # 0 or more unwind { ... }; # 0 or 1 The basic semantics are: * The try clause is evaluated. * Each catch clause is invoked, but only if an exception has been raised since the beginning of the try statement, and the catch clause's except TEST is true or is not given. * Each finally clause is invoked whether or not an exception has been raised since the beginning of the try statement. * The unwind clause, if any, is invoked if an exception has been raised since the beginning of the try statement, and it has not been cleanly caught. * After processing all clauses, try unwinds (dies) iff any exception wasn't cleanly caught. An exception is considered to be "cleanly caught" if it was in the try clause, and it triggered a catch clause, and no catch or finally clause raised an exception. Yours, c, Tony Olekshy
Re: RFC 80 (v1): Exception objects and classes for builtins
On Thu, Aug 10, 2000 at 06:43:30PM -0400, Chaim Frenkel wrote: "GB" == Graham Barr [EMAIL PROTECTED] writes: GB On Thu, Aug 10, 2000 at 04:34:50PM -0400, Chaim Frenkel wrote: Nice. The continue clause, I assume would re-raise an uncaught exception. But, a big but. How does the 'else' clause indicate that the exception was handled? GB By not rethrowing it. ie if it does not want to handle the GB error itself it just callsdie; GB Which will call PROPAGATE on the object in $@, just like perl5, then GB look back up the call-stack for the next eval { } Hmm, we must be coming from different backgrounds. I expect my exception handler to rethrow if not handled. I expect the continue block to be run under both conditions, and be responsible for ensuring consistancy. Let's look at it from how the validity of the data (or object) # -- Invariant True eval { # -- Invariant True # -- Invariant True } else { # -- Invariant might be invalid ... # -- } continue { # -- ... # -- Invariant True } # -- Invariant True What would you want at the exit point of the else or the entry point of the continue? Is the job of the continue to restore the invariant or is it the job of the else clause. The else it catching the errors. Remeber that with perls eval it is upto you to deal with $@, perl does not magically die again if you do nothing as you can ignore it if you want to. So following on from that the else block deals with the error if it wants to. One of it's options is to pass it on up the call stack. The otherwise will always be called on exit of the else block, whether it be exiting by a natural path or by calling die. Graham.
Re: RFC 80 (v1): Exception objects and classes for builtins
On Thu, Aug 10, 2000 at 07:30:53PM -0700, Peter Scott wrote: So I'm thinking: eval { ... } catch Exception::Foo { ... } catch Exception::Bar, Exception::Baz { ... } catch { ... # everything else, but if this block is absent, uncaught exceptions # head up the call stack } continue { ... # Executed after everything } I maybe warming to this idea. If we're really talking about new keywords, we wouldn't need a ; at the end of the last block; it's only needed at the moment because eval is a function, not a keyword. I would vote for the keywords only because people are going to forget the ; otherwise. That maybe a reason to use `try' instead of `eval'. Another difference would be that try will rethrow uncaught error, eval does not. And of course a die in any catch block would throw an error to a try/eval block up the stack, after running the continue block. So adie; in the catch block would rethrow the same error. I like reusing 'continue' since I use 'finally' blocks about as often as I use 'continue' blocks anyway :-) Right. Graham.
Re: RFC 80 (v1): Exception objects and classes for builtins
On Thu, Aug 10, 2000 at 07:47:47PM -0600, Tony Olekshy wrote: With the approach proposed in RFC 88 (Structured Exception Handling Mechanism), you could write that as: try { } catch { switch ($_[0]-name) { case IO { ... } case Socket { ... } } } Nope, the error are objects, so you need to allow for inheritance. Graham.
Re: RFC 80 (v1): Exception objects and classes for builtins
Graham Barr wrote: If we're really talking about new keywords, we wouldn't need a ; at the end of the last block; it's only needed at the moment because eval is a function, not a keyword. I would vote for the keywords only because people are going to forget the ; otherwise. That maybe a reason to use `try' instead of `eval'. Another difference would be that try will rethrow uncaught error, eval does not. And of course a die in any catch block would throw an error to a try/eval block up the stack, after running the continue block. So adie; in the catch block would rethrow the same error. I support the idea of renaming the block eval as die, and leaving eval for string eval. But I'm against the idea of implicit rethrowing in any case. Sure, other languages do it, but perl doesn't, and personally I think it's a better paradigm. If you really want to rethrow unhandled exceptions, you can always catch { die } -- John Porter
Re: RFC 80 (v1): Exception objects and classes for builtins
John Porter [EMAIL PROTECTED] writes: Piers Cawley wrote: The (continue|always|finally|whatever) clause will *always* be executed, even if one of the catch clauses does a die, so you can use this to roll back the database transaction or whatever else was going on and restore any invariants. Which makes me think that it would be nice if the continue block could come before the catch block(s): establish_invariants(); try { something_risky(); } continue { restore_invariants(); } catch { handle_error_assuming_invariants_restored(); } Hmm... that doesn't really fit with me too well, kind of the wrong meaning for continue somehow. Somebody suggested unwind: try { something_risky() } unwind { restore_invariants() } catch { $@-handle() } continue { do_continuation; } Hmm... it gets convoluted doesn't it? -- Piers
Re: RFC 80 (v1): Exception objects and classes for builtins
"PC" == Piers Cawley [EMAIL PROTECTED] writes: PC The (continue|always|finally|whatever) clause will *always* be PC executed, even if one of the catch clauses does a die, so you can use PC this to roll back the database transaction or whatever else was going PC on and restore any invariants. Err, how does one differentiate between a 'good' entry and a 'bad' entry. PC Note too that we don't need to do any case based magic, we can and PC should use polymorphism for that. Why? Just because? chaim -- Chaim FrenkelNonlinear Knowledge, Inc. [EMAIL PROTECTED] +1-718-236-0183
Re: RFC 80 (v1): Exception objects and classes for builtins
Chaim Frenkel [EMAIL PROTECTED] writes: "PC" == Piers Cawley [EMAIL PROTECTED] writes: PC The (continue|always|finally|whatever) clause will *always* be PC executed, even if one of the catch clauses does a die, so you can use PC this to roll back the database transaction or whatever else was going PC on and restore any invariants. Err, how does one differentiate between a 'good' entry and a 'bad' entry. Um, if the try block completed without tripping a catch clause then it worked. If it didn't, then it didn't. If you want to be able to have the continue block not unwind on some occasions then have it check the value of $@. PC Note too that we don't need to do any case based magic, we can and PC should use polymorphism for that. Why? Just because? Good OO programming practice. Use polymorphism to replace switches. Then when you subclass one of your classes you don't have to go 'round rejigging the switch statements. -- Piers
Re: RFC 80 (v1): Exception objects and classes for builtins
At 10:34 AM 8/11/00 -0400, John Porter wrote: But I'm against the idea of implicit rethrowing in any case. Sure, other languages do it, but perl doesn't, and personally I think it's a better paradigm. We may have to disagree. If you don't have a clause to catch an exception, semantically, it hasn't been caught, so why would you need to explicitly rethrow it? If the implementation needs to catch it anyway, that's the implementation's problem. -- Peter Scott Pacific Systems Design Technologies
Re: RFC 80 (v1): Exception objects and classes for builtins
On Fri, Aug 11, 2000 at 10:26:25AM -0700, Peter Scott wrote: At 10:34 AM 8/11/00 -0400, John Porter wrote: But I'm against the idea of implicit rethrowing in any case. Sure, other languages do it, but perl doesn't, and personally I think it's a better paradigm. We may have to disagree. If you don't have a clause to catch an exception, semantically, it hasn't been caught, so why would you need to explicitly rethrow it? If the implementation needs to catch it anyway, that's the implementation's problem. Which is why catch is the wrong word. In perl eval{} (or try) does `catch' the error Graham.
Re: RFC 80 (v1): Exception objects and classes for builtins
"PC" == Piers Cawley [EMAIL PROTECTED] writes: PC Good OO programming practice. Use polymorphism to replace switches. Then PC when you subclass one of your classes you don't have to go 'round PC rejigging the switch statements. I haven't used OO in anger. But for me polymorphism is action-at-distance of the worst stripe. Its the cheap and dirty way of doing OO. Let the object determine the calling convention for the method. I see very little reason to have two methods with different signatures. chaim -- Chaim FrenkelNonlinear Knowledge, Inc. [EMAIL PROTECTED] +1-718-236-0183
Re: RFC 80 (v1): Exception objects and classes for builtins
Chaim Frenkel wrote: Let the object determine the calling convention for the method. I see very little reason to have two methods with different signatures. Yes! That's the Perl philosophy! Right on! -- John Porter
Re: RFC 80 (v1): Exception objects and classes for builtins
Chaim Frenkel wrote: [ ... ] for me polymorphism is action-at-distance of the worst stripe. Its the cheap and dirty way of doing OO. [...] I see very little reason to have two methods with different signatures. Method signatures and polymorphism are orthogonal. The latter refers to different classes having differing implementations of a method of the same name (often via inheritance and overriding) and/or name + signature. Say you had a base class for exception objects that defines a method that returns whether or not Foo is true for that class. Say you derive a descendent class from that base class via inheritance, and then extended the derived class to add a new instance variable. Say you then, in your derived class, override the method that returns whether or not Foo is true to take your new instance variable into account. With polymorphism, one doesn't have to know whether one has an instance of the base class or an instance of the derived class (using kludgery such as isa), one can just say $o-IsFoo and both cases work as per Fooing. Signatures don't need to enter into it. For more information see http://www.cyberdyne-object-sys.com/oofaq2/body/typing.htm#S2.1 Yours, c, Tony Olekshy
Re: RFC 80 (v1): Exception objects and classes for builtins
At 02:56 AM 8/10/00 -0500, Jonathan Scott Duff wrote: Peter Scott writes: try { # fragile code } catch Exception::IO with { # handle IO exceptions } catch Exception::Socket with { # handle network exceptions } otherwise { # handle other exceptions }; What would the difference between that and this be? try { # fragile code } catch { # catch ALL exceptions switch ($EXCEPTION-name) { case IO { ... } case Socket { ... } } } The catch clause would catch all exceptions. The one thrown would be placed in a "global" $EXCEPTION variable. TMTOWTDI, I guess. The exception variable comes into the catch block as $_[0] in Error.pm. To catch all exceptions you'd just use an otherwise clause. This is a strawman exception class hierarchy. The merits of this RFC do not depend on this beign a good hierarchy, only on it being possible to find a reasonable one. Is it really a hierarchy? Must it be? Your strawman looks more like an enumeration to me. You're right, the places where I suggested subclassing wouldn't really be subclasses, just an extra :: in the name to imply containership. Unless the exception classes had some semantics I hadn't thought of, in which case they could be inherited. Good point, I shall fix it in v2. -- Peter Scott Pacific Systems Design Technologies
Re: RFC 80 (v1): Exception objects and classes for builtins
On Thu, Aug 10, 2000 at 02:56:59AM -0500, Jonathan Scott Duff wrote: Peter Scott writes: try { # fragile code } catch Exception::IO with { # handle IO exceptions } catch Exception::Socket with { # handle network exceptions } otherwise { # handle other exceptions }; What would the difference between that and this be? try { # fragile code } catch { # catch ALL exceptions switch ($EXCEPTION-name) { case IO { ... } case Socket { ... } } } I was more thinking of eval { # fragile code } else { # catch ALL exceptions switch ($@) { case __-isa('IO') { ... } case __-isa('Socket') { ... } else { ... } } } continue { # code always executed (ie finally) } And the only new keywords are for the switch statement. Graham.
Re: RFC 80 (v1): Exception objects and classes for builtins
On Thu, Aug 10, 2000 at 09:34:43AM -0700, Peter Scott wrote: At 05:11 PM 8/10/00 +0100, Graham Barr wrote: I was more thinking of eval { # fragile code } else { # catch ALL exceptions switch ($@) { case __-isa('IO') { ... } case __-isa('Socket') { ... } else { ... } } } continue { # code always executed (ie finally) } And the only new keywords are for the switch statement. Do you propose this solely to conserve keywords, partly or is there another advantage? I find try { # } catch Exception::Thingy with { # } catch Exception::Whatsit with { # } otherwise { # }; considerably more appealing, especially since catch blocks can contain tens of statements. It's easier to see the exception class (not tucked inside a method call), and there aren't additional block levels. Well what is the difference between try and eval ? The catch syntax is less flexable, if you wanted to catch two different types with the same code you are forced to either * duplicate code * put it in a sub, which is away from the statement. This may not help readability * put a switch statement in the otherwise In fact the syntax could be eval { } continue { } switch ($@) { } if $@; I just don't see the need to make perl look like other languages just for the sake of makeing it look like other languages. Graham.
Re: RFC 80 (v1): Exception objects and classes for builtins
Graham Barr wrote: The catch syntax is less flexable, if you wanted to catch two different types with the same code you are forced to either * duplicate code * put it in a sub, which is away from the statement. * put a switch statement in the otherwise Could catch lists of types: try { } catch Exception::Thingy, Exception::Whingy with { -- John Porter
Re: RFC 80 (v1): Exception objects and classes for builtins
On Thu, 10 Aug 2000 09:34:43 -0700, Peter Scott wrote: Do you propose this solely to conserve keywords, or is there another advantage? I find try { # } catch Exception::Thingy with { # } catch Exception::Whatsit with { # } otherwise { # }; considerably more appealing, especially since catch blocks can contain tens of statements. I find it pretty ridiculous. Why "otherwise" instead of "else"? This *is* some kind of switch statement; if Perl is to have a general syntax for switch statements, it should be employed for error trapping as well. p.s. I've always disliked the word "throwing" for errors, just to be a complement to "catch". An error to me is something like a trapdoor, where you unexpectedly fall through. -- Bart.
Re: RFC 80 (v1): Exception objects and classes for builtins
Nice. The continue clause, I assume would re-raise an uncaught exception. But, a big but. How does the 'else' clause indicate that the exception was handled? A couple of possiblities 1. Undef $@. But that's a bit of extra work in each leg. 2. switch is 'slightly' special in an eval/else block. If the case selects the error, then it is considered handled unless a die or redo is encountered. 3. If continue is not being used by Damian's switch, then a continue continues onto the continue block, and marks the successful handling of the exception. chaim "GB" == Graham Barr [EMAIL PROTECTED] writes: GB I was more thinking of GB eval { GB # fragile code GB } GB else { # catch ALL exceptions GB switch ($@) { GB case __-isa('IO') { ... } GB case __-isa('Socket') { ... } GB else { ... } GB } GB } GB continue { GB# code always executed (ie finally) GB } GB And the only new keywords are for the switch statement. -- Chaim FrenkelNonlinear Knowledge, Inc. [EMAIL PROTECTED] +1-718-236-0183
Re: RFC 80 (v1): Exception objects and classes for builtins
"GB" == Graham Barr [EMAIL PROTECTED] writes: GB On Thu, Aug 10, 2000 at 04:34:50PM -0400, Chaim Frenkel wrote: Nice. The continue clause, I assume would re-raise an uncaught exception. But, a big but. How does the 'else' clause indicate that the exception was handled? GB By not rethrowing it. ie if it does not want to handle the GB error itself it just callsdie; GB Which will call PROPAGATE on the object in $@, just like perl5, then GB look back up the call-stack for the next eval { } Hmm, we must be coming from different backgrounds. I expect my exception handler to rethrow if not handled. I expect the continue block to be run under both conditions, and be responsible for ensuring consistancy. Let's look at it from how the validity of the data (or object) # -- Invariant True eval { # -- Invariant True # -- Invariant True } else { # -- Invariant might be invalid ... # -- } continue { # -- ... # -- Invariant True } # -- Invariant True What would you want at the exit point of the else or the entry point of the continue? Is the job of the continue to restore the invariant or is it the job of the else clause. chaim -- Chaim FrenkelNonlinear Knowledge, Inc. [EMAIL PROTECTED] +1-718-236-0183
Re: RFC 80 (v1): Exception objects and classes for builtins
At 07:53 PM 8/10/00 +0200, Bart Lateur wrote: p.s. I've always disliked the word "throwing" for errors, just to be a complement to "catch". An error to me is something like a trapdoor, where you unexpectedly fall through. The only difference is the direction of travel :-) In both cases you don't know where you're going to land. -- Peter Scott Pacific Systems Design Technologies
Re: RFC 80 (v1): Exception objects and classes for builtins
At 10:33 PM 8/10/00 +0100, Graham Barr wrote: On Thu, Aug 10, 2000 at 04:34:50PM -0400, Chaim Frenkel wrote: Nice. The continue clause, I assume would re-raise an uncaught exception. But, a big but. How does the 'else' clause indicate that the exception was handled? By not rethrowing it. ie if it does not want to handle the error itself it just callsdie; So the user always has to put a die in an else block in the switch if they want uncaught exceptions rethrown? Ugh. The catch LIST { block } is more intuitive. Surely choosing exception classes for catch blocks does not get so complex that we want to use the firepower of the switch statement at the cost of usability? We can dispense with the 'with' keyword, of course. So I'm thinking: eval { ... } catch Exception::Foo { ... } catch Exception::Bar, Exception::Baz { ... } catch { ... # everything else, but if this block is absent, uncaught exceptions # head up the call stack } continue { ... # Executed after everything } If we're really talking about new keywords, we wouldn't need a ; at the end of the last block; it's only needed at the moment because eval is a function, not a keyword. I would vote for the keywords only because people are going to forget the ; otherwise. I like reusing 'continue' since I use 'finally' blocks about as often as I use 'continue' blocks anyway :-) -- Peter Scott Pacific Systems Design Technologies
Re: RFC 80 (v1): Exception objects and classes for builtins
Peter Scott wrote: So I'm thinking: eval { ... } catch Exception::Foo { ... } catch Exception::Bar, Exception::Baz { ... } catch { ... # everything else, but if this block is absent, uncaught exceptions # head up the call stack } continue { ... # Executed after everything } If we're really talking about new keywords, we wouldn't need a ; at the end of the last block; it's only needed at the moment because eval is a function, not a keyword. I would vote for the keywords only because people are going to forget the ; otherwise. Hooray! The trailling ';' required by error.pm is evil and must be destroyed before drives us all into madness!