From: <dg...@us...> - 2008-12-09 18:10:43
|
A niggly detail on this one. The TIP describes [throw] as the same as [error] but with the argument order revised. However, the reference implementation doesn't quite match that description. In particular, the [error] command always produces the TCL_ERROR return code. The implemented [throw] always produces the TCL_RETURN return code. I think I'd prefer what the TIP proposes over what's implemented. In fact, I think it may be necessary to make that correction for simple test cases of [try {throw...}] to work as expected. A simple way to do that (without full syntax checking) is interp alias {} throw {} return -level 0 -code error -errorcode DGP |
From: Andreas L. <av...@lo...> - 2008-12-12 08:28:22
|
Twylite <tw...@cr...> wrote: > - removed the 'as {resultsVar optionsVar}' clause and introduced > per-handler variable assignment An unfortunate decision that was rushed into the TIP just before voting. Three reasons against it: - Tcl's variables outlive their specific handler block. They even outlive the whole try-construct. As such they are not at all comparable to e.g. Java's try/catch where these variables only exist inside their respective handler. - Originally (with "as ..."), these variables would have been also available in the finally block. Now, they are available depending on whether and which other handler fired, and can never be relied on. - The (only now showing up) problem with "-". Joe English <jen...@fl...> wrote: > > Option #1: set the FOO case variables only; making sure the body works > > correctly is the developer's problem > Option #1 is what the TIP specifies should happen. > > Option #2: set the BAR case variables only; the fact that the FOO > > variables are left unset is a quirk of using the "-" syntax Option #2a: make "-" be recognized in place of the variable list. > I for one would not object to a corrigendum specifying > option #2, but for now it's probably best to make the > implementation match the specification. If a corrigendum was still possible, I'd prefer: Option #Omega: reinstate the "as"-clause. I wonder, who of the voters had their vote depending on the way of variable handling. |
From: Twylite <tw...@cr...> - 2008-12-12 09:08:47
|
Hi, >> - removed the 'as {resultsVar optionsVar}' clause and introduced >> per-handler variable assignment >> > An unfortunate decision that was rushed into the TIP just before voting. > Three reasons against it: > I was expecting this reply ;) The counterpoints have already been presented. I think there are strong arguments both ways, and I don't think either approach is a clear winner. Per-handler variables was part of my original plan for the TIP; fall-through bodies wasn't. Had the TCT not put their feature freeze at the crunch point of my two biggest projects I may have got the handling of "-" correct in the TIP ;) > Option #2a: make "-" be recognized in place of the variable list. > Yes, definitely worth considering. I think that Option #1 (use FOO's variable list and BAR's body) is unworkable. Option #2 (BAR's list & body) leaves an unused variable list attached to FOO, which is just weird. Either FOO's variable list must go away (require "-" if the body is "-") or both FOO and BAR's variables must be set (I don't know if this is somehow more useful). > If a corrigendum was still possible, I'd prefer: > > Option #Omega: reinstate the "as"-clause. > try -mode tip329 ... try -mode option1 ... try -mode omega ... C'mon, you know you want to ... ;> (Aside: we can still add the "as" clause later, if desired. It would be an optional clause between the try body and the first handler, and would not replace per-handler variable lists, but be set in addition to any variables in those lists. There's also [catch] ...) Twylite |
From: Andreas L. <av...@lo...> - 2008-12-12 12:52:58
|
On Fri, Dec 12, 2008 at 11:08:30AM +0200, Twylite wrote: > The counterpoints have already been presented. I think there are strong > arguments both ways, I'm definitely biased, but the only argument for handler-specific variables, that I found in the discussion was that all the other languages (especially Java) have per-handler variables. That one isn't strong in my mind. Did I miss other arguments? (It would really surprise me, if implementation effort wasn't rather an argument *for* the "as ..."-clause instead of against, but I may of course be wrong there) > >Option #Omega: reinstate the "as"-clause. > try -mode tip329 ... > try -mode option1 ... > try -mode omega ... > C'mon, you know you want to ... ;> Nice revanche for my previous personal mix-up, (for which I apologized recently). I'm not the options-fancier. No, I honestly would not advocate any such options (not even with better names) > (Aside: we can still add the "as" clause later, if desired. I'd indeed desire that, on position 2 (right after #1: "also drop the per-handler variable lists"). Leaving it as in the TIP would be position 3, and no-"try"-at-all somewhere near 1000 followed only by -option'ed versions of "try". > There's also [catch] ...) Oh really? I thought that was being replaced... (just kidding :-) |
From: Andreas L. <av...@lo...> - 2008-12-12 12:23:21
|
On Fri, Dec 12, 2008 at 01:07:34PM +0100, Andreas Leitgeb wrote: > > (Aside: we can still add the "as" clause later, if desired. > I'd indeed desire that, on position 2 (right after #1: "also > drop the per-handler variable lists"). Leaving it as in the > TIP would be position 3, and no-"try"-at-all somewhere near > 1000 followed only by -option'ed versions of "try". Small correction: position 3 is TIP with option #2a, (which is either "trap FOO - - BAR {x y} { body }" or "trap FOO - BAR {x y} { body }" i.e. one dash replacing both variable list and body together unless it was much more complicated to implement.) Current TIP is, as you wrote yourself, "unworkable". |
From: Joe E. <jen...@fl...> - 2008-12-12 17:40:00
|
Andreas Leitgeb wrote: > Twylite wrote: > > The counterpoints have already been presented. I think there are strong > > arguments both ways, > > I'm definitely biased, but the only argument for handler-specific > variables, that I found in the discussion was that all the other > languages (especially Java) have per-handler variables. > > That one isn't strong in my mind. Did I miss other arguments? Specific example: try { open $filename r } on ok {fp} { # ... } on error {msg opts} { # ... } (Which was one of the motivating use cases for dispatching based on return code in the first place.) With try/as, this would be: try { open $filename r } as {xxx opts} on ok { # (1) here $xxx is a file channel. } on error { # (2) here $xxx is an error message. } # (3) For the sake of clarity, I'd want to use different variable names in the two handler clauses -- "fp" for the case where the result is a file channel, "msg" for the case where it's an error message. (I can't think of a good variable name to use in the "as" clause.) At point (3), you know that $xxx and $opts are set to _something_, but you don't know what. You usually don't care, either. --Joe English jen...@fl... |
From: Twylite <tw...@cr...> - 2008-12-12 13:39:26
|
Hi, > That one isn't strong in my mind. Did I miss other arguments? > 1. There were a number of "complaints" (both here and off-list) that the 'as' clause was ugly to format. I'm inclined to agree and it was one of the reasons I resisted 'as' in the first place. I believe that code readability is an important feature, and consistency (of syntax & of layout) aids readability. 2. Locality: associating the variable with the handler gives more immediate knowledge of what the variable names are, and allows the variable names to be contextually appropriate. Example: try { open "somefile.txt" r } on ok {f} { puts $f "hello" } trap {} {errmsg} { log "Failed: $errmsg" } 3. Easier to reuse handlers: if the vars are associated with the handler it becomes easier to reuse handlers either by storing the handlers as a string or by cut/paste/adapt. In my experience a huge amount of error handling code is cut/paste/adapt, and a major source of errors for junior coders is bad variable names in error handlers (whether from cut & paste or simple mistyping; compiled environments pick this up, Tcl doesn't until you hit an error or test every error path via fault injection), so avoiding or reducing such errors is a major win. 4. Familiarity: it's what other languages do. 5. It's the safer approach. It is possible to add 'as' later, but it is not possible to add per-handler variables later. If we do add 'as' and the per-handler variables are mostly unused it becomes a syntactic quirk that we can & will live with. Comparing to the points you made, the choice of which is "better" is determined largely by what importance/weight you assign to various features and "misfeatures". > (It would really surprise me, if implementation effort wasn't > rather an argument *for* the "as ..."-clause instead of against, > but I may of course be wrong there) > It's kindof neither here nor there. The (pure Tcl) implementation is different but no more or less complex - it's a matter of putting the varslist parsing + upvar + assignment inside or outside a loop. >> There's also [catch] ...) >> > Oh really? I thought that was being replaced... (just kidding :-) > <[catch]> Rumors of my demise have been greatly exaggeraaughhhh--- Regards, Twylite |
From: Fredderic <mag...@gm...> - 2008-12-14 22:28:39
Attachments:
signature.asc
|
On Fri, 12 Dec 2008 15:39:07 +0200, Twylite <tw...@cr...> wrote: >> That one isn't strong in my mind. Did I miss other arguments? > 1. There were a number of "complaints" (both here and off-list) that > the 'as' clause was ugly to format. I'm inclined to agree and it was > one of the reasons I resisted 'as' in the first place. I believe > that code readability is an important feature, and consistency (of > syntax & of layout) aids readability. That's why one of my earlier renditions had a -withvars type option BEFORE the main body. I only revised that to going with the "as" keyword because people didn't like that option. You could perhaps borrow a reference to [proc], and format [try] like this: try as {?resVar ?optVar??} { ...script... } ?handlers ...? although it _really_ doesn't work with issue #2 below... I'd quite happily use it. > 2. Locality: associating the variable with the handler gives more > immediate knowledge of what the variable names are, and allows the > variable names to be contextually appropriate. > Example: try { open "somefile.txt" r } on ok {f} { puts $f "hello" } > trap {} {errmsg} { log "Failed: $errmsg" } The first part of this point is just pathetic. The second part, contextually appropriate naming, has _some_ merit. Although simply chosing generic names in the first place like we've always had to do with [catch] is still better. If you're really desperate, either [upvar 0] the names within the handler body, or wrap it with [apply] (isn't there an [invoke] command in the works, also...? That could well be applicable here also). > 3. Easier to reuse handlers: if the vars are associated with the > handler it becomes easier to reuse handlers either by storing the > handlers as a string or by cut/paste/adapt. In my experience a huge > amount of error handling code is cut/paste/adapt, and a major source > of errors for junior coders is bad variable names in error handlers > (whether from cut & paste or simple mistyping; compiled environments > pick this up, Tcl doesn't until you hit an error or test every error > path via fault injection), so avoiding or reducing such errors is a > major win. That's what [proc] and [apply] are for. If you implement [try] in the slightly backwards fashion I described above, then a simple [interp alias] lets you pre-package standard variable names. interp alias {} try-standard {} try as {retvar optvar} try-standard { ...script... } ...handlers... This reminds me of the handler-in-a-variable idea... try {script} $::HANDLER ... That particular idea trashes the crap out of reason #1 in this list, if the handler body is included in the variable, how the heck do you format a bunch of handlers like that cleanly?!? And while you're at it, if you can't even "adapt" the variable names, how do you make sure there's no variable name collisions against the enclosing scope? That looks like an absolute hornets-nest of trouble to me. Better to discourage that and encourage wrapping the handlers in [proc] or [apply]. Constructing a builder for that wouldn't be hard at all: proc try-handler {args} { if { [llength $args] <= 2 } { error "wrong # args: should be \"... {retvar optvar} script\"" } set var [lrange $args 0 end-2] lappend var [lrange $args end-1 end] } If you wanted to, though, that could be a candidate for a new verb: apply $::HANDLER a list of everything that would normally be there, except that the last one is a lambda given two arguments. It'd mash any hope of compilation, but then I suspect that whole handler-in-a-variable idea already does that anyhow. You could conceivably go one step further and have a secondary script block which is evaluated after the one in the hander package. The case of an empty secondary script would rather neatly bridge it to another line, helping with the uglyness factor. I wonder what the chances of getting a {@} syntax that causes a compile-time substitution... Whatever it preceeds would be evaluated, substituted, and then compiled in as though it was already there, fixing whatever value it returned at that time. Could get a little strange if the value changes between when the script was specified, and when it gets compiled, but it'd be useful when used with care. (Probably about as much chance as {n} as an [lindex ... $n] alternative...) > 4. Familiarity: it's what other languages do. Who gives a crap, honestly. Using that as an argument is almost as pathetic as "oh darnit, I went and forgot what the variable names were". > 5. It's the safer approach. It is possible to add 'as' later, but it > is not possible to add per-handler variables later. If we do add > 'as' and the per-handler variables are mostly unused it becomes a > syntactic quirk that we can & will live with. It IS possible if you have the per-handler variables as an option, as I pointed out ages ago also: -vars {retvar optvar} I know you aren't a fan of options, but there's room for them here. I'd agree with you if the next word after the options could be the name of a variable. But when it's a script, and usually a hard-coded one at that, plus a statement line that's typically going to be fairly short, it just doesn't make sense to go to such extents simply to avoid them. The ONLY case where the sentinel option will be needed, is if the script is supplied by variable and might possibly be a bizarrly named command taking no arguments. And in such cases, all reasons against having a sentinel option really don't matter a whole lot any more. Basically, with the -vars option, it goes like this; if the "as" verb is present, use it. If the -vars option is present, use it also (just as we would be for the per-handler variables at present). Heck, you could even have two versions of the -vars option; one which defines the variables if this exact handler matches, before it gets to the handler body (and regardless of whether there actually is a body for this handler or not). The other effectively pre-pends assigning the variables, onto the start of the handler body (if combined with the "-" fall-through body, it would presumably do the assignment then jump on down to the next body, potentially leaving a whole series of variables holding the values). And for those concerned about getting this into production as quickly as possible, add the "as" verb and handling for the "--" sentinel option. The rest can be implemented later, in particular, once you've figured out just what to do with the per-handler vars, they can be patched into the current CVS version as options, and brought through in the next release as an alternative. >> (It would really surprise me, if implementation effort wasn't >> rather an argument *for* the "as ..."-clause instead of against, >> but I may of course be wrong there) > It's kindof neither here nor there. The (pure Tcl) implementation is > different but no more or less complex - it's a matter of putting the > varslist parsing + upvar + assignment inside or outside a loop. I believe ages ago I said that's how I expected it'd all work out... >>> There's also [catch] ...) >> Oh really? I thought that was being replaced... (just kidding :-) > <[catch]> Rumors of my demise have been greatly exaggeraaughhhh--- Personally, I still reckon attaching the handlers to the end of [catch] is a perfectly sane option. But then you know, I'm starting to get the impression that I'm a little unusual around these parts. On Fri, 12 Dec 2008 09:39:54 -0800, Joe English <jen...@fl...> wrote: > With try/as, this would be: > try { > open $filename r > } as {xxx opts} on ok { > # (1) here $xxx is a file channel. > } on error { > # (2) here $xxx is an error message. > } > For the sake of clarity, I'd want to use different variable > names in the two handler clauses -- "fp" for the case where > the result is a file channel, "msg" for the case where it's > an error message. (I can't think of a good variable name to > use in the "as" clause.) How about resp and opts. I've been using them (well, resp, at least) with [catch] statements for about as long as I've known been using the [catch] statement. In your example, $xxx is the result of evaluating the main script, whatever that may be. It's really not that complicated... And with both an optional "as" verb, and the per-handler vars (be it a mandatory argument or a -vars option), then you really can have your cake and eat it too. -- Fredderic Before you criticize someone walk a mile in their shoes. That way, when you criticize them you're a mile away and you have their shoes. Debian/unstable (LC#384816) on i686 2.6.23-z2 2007 (up 11 days, 8:40) |
From: Andreas L. <av...@lo...> - 2008-12-12 14:00:40
|
On Fri, Dec 12, 2008 at 03:39:07PM +0200, Twylite wrote: > Hi, > >That one isn't strong in my mind. Did I miss other arguments? > [ list of (some more and some less-but-still) valid arguments > acknowledged ] Ok, I now understand also the advantages of per-handler variables. Thanks a lot. Is "Option #2a" implementable, and will we need one or two dashes per (forwarding) handler? PS: I'm nevertheless looking forward for an optional "as" clause in hopefully not-too-far future. |
From: Twylite <tw...@cr...> - 2008-12-12 14:11:36
|
Hi, > Is "Option #2a" implementable, and will we need one or two dashes > per (forwarding) handler? > The most likely implementation is a check that varslist must be {} if body is "-". e.g. try { ... } on break {} - on continue {em opts} { ...handler for break and continue, gets em+opts... } I could allow varslist to be {} or "-" in such a case -- it's prettier, but "-" is in fact a valid varslist (assigns the result to the local variable "-"). e.g. try { ... } on break - - on continue {em opts} { ...handler for break and continue, gets em+opts... } > PS: I'm nevertheless looking forward for an optional "as" clause > in hopefully not-too-far future. > I'm hoping to put the Tcl implementation into tcllib (possible in the control package), giving [try] functionality to Tcl 8.5. This will then be an appropriate place to experiment with new features (like 'as'). From there I imagine they may be TIPped into the core. Regards, Twylite |
From: Andreas L. <av...@lo...> - 2008-12-13 18:49:07
|
Joe English <jen...@fl...> wrote: > Andreas Leitgeb wrote: > > I'm definitely biased, but the only argument for handler-specific > > variables, that I found in the discussion was that all the other > > languages (especially Java) have per-handler variables. > Specific example: Twylite already answered my question, and he also gave better reasons than that one, so I declared my defeat on this topic already. ;-) > At point (3), you know that $xxx and $opts are set to _something_, > but you don't know what. You usually don't care, either. Without the intention to reopen the discussion, with per handler variable lists, not only do I not know what a variable really contains (error-message or return-value), but also don't know which variables were actually set in the try. PS: I'd have called the variable "retval" or just "rv" instead of "xxx" and would probably do so if an "as ..." clause is ever added as optional clause, later. PPS: most of the cases, I'd place the "on ok"-body right into the try-body, so the different interpretation of the variable would not be a problem most of the times. |
From: Donald G P. <dg...@ni...> - 2008-12-09 18:38:34
|
dg...@us... wrote: > ...In fact, I think > it may be necessary to make that correction > for simple test cases of [try {throw...}] to > work as expected. Confirmed: % try {throw FOO bar} trap FOO {puts zing!} bar % try {return -level 0 -code error -errorcode FOO bar} trap FOO {puts zing!} zing! Assuming the actual committed implementation will correct that problem... TIP 329: YES -- | Don Porter Mathematical and Computational Sciences Division | | don...@ni... Information Technology Laboratory | | http://math.nist.gov/~DPorter/ NIST | |______________________________________________________________________| |
From: Twylite <tw...@cr...> - 2008-12-09 19:06:14
|
Hi, > A niggly detail on this one. The TIP > describes [throw] as the same as [error] > but with the argument order revised. > > However, the reference implementation > doesn't quite match that description. > Confirmed - this is an error in the implementation. > interp alias {} throw {} return -level 0 -code error -errorcode > Seems like the right thing to me. Thanks - I'll update the implementation. Regards, Twylite |
From: Twylite <tw...@cr...> - 2008-12-12 00:09:07
|
Okay, I found some time to work on the reference implementation. Changes: - 'throw' has behavior consistent with 'error'. The 'interp alias' approach that was suggested behaves weirdly if you don't get the arguments right, so the implementation is proc-based. - removed the 'as {resultsVar optionsVar}' clause and introduced per-handler variable assignment - improved error messages - improved behavior of '-during' - added tests (there are just under 100 tests covering most aspects of the functionality; more to come) Outstanding issues: - In the case of a fallthrough body "-", to which variable(s) should the outcome of the try body be assigned? e.g. try { throw FOO bar } trap FOO {em1 opts1} - trap BAR {em2 opts2} { puts body } It seems logical that the variables for the BAR case may be expected by the BAR body and should be set; but what about those for the FOO case? Option #1: set the FOO case variables only; making sure the body works correctly is the developer's problem Option #2: set the BAR case variables only; the fact that the FOO variables are left unset is a quirk of using the "-" syntax Option #3: set the FOO and BAR variables; possibly more consistent from the developer's perspective, but adds complexity to any implementation that is aiming for performance Option #4: sets the FOO and BAR variables as well as those of any other fallthrough cases in between, also at a cost in complexity/performance terms The current implementation provides Option #2, but this is strictly a side-effect of the implementation and easily changed to #1 or #4 (#3 is a bit of a pain). - Some corner cases around when "-during" should or should not be added to the options dict. Updated version available at http://www.crypt.co.za/pub/try-2.tcl . Regards, Twylite |
From: Joe E. <jen...@fl...> - 2008-12-12 04:44:43
|
Twylite wrote: > Outstanding issues: > - In the case of a fallthrough body "-", to which variable(s) should the > outcome of the try body be assigned? > e.g. try { throw FOO bar } trap FOO {em1 opts1} - trap BAR {em2 opts2} > { puts body } > It seems logical that the variables for the BAR case may be expected by > the BAR body and should be set; but what about those for the FOO case? > > Option #1: set the FOO case variables only; making sure the body works > correctly is the developer's problem Option #1 is what the TIP specifies should happen. > Option #2: set the BAR case variables only; the fact that the FOO > variables are left unset is a quirk of using the "-" syntax This would also be sensible, and possibly more useful, but it's not what the TIP says. > Option #3: set the FOO and BAR variables; possibly more consistent from > the developer's perspective, but adds complexity to any implementation > that is aiming for performance > Option #4: sets the FOO and BAR variables as well as those of any other > fallthrough cases in between, also at a cost in complexity/performance terms The last two options don't strike me as either sensible or useful. > The current implementation provides Option #2, but this is strictly a > side-effect of the implementation and easily changed to #1 or #4 (#3 is > a bit of a pain). #1 is what the TIP says. #2 would also be reasonable (and, now that I think about it, probably a better choice). I for one would not object to a corrigendum specifying option #2, but for now it's probably best to make the implementation match the specification. --Joe English jen...@fl... |
From: Fredderic <mag...@gm...> - 2008-12-14 17:10:26
Attachments:
signature.asc
|
On Fri, 12 Dec 2008 02:08:40 +0200, Twylite <tw...@cr...> wrote: > Okay, I found some time to work on the reference implementation. > > Changes: > - 'throw' has behavior consistent with 'error'. The 'interp alias' > approach that was suggested behaves weirdly if you don't get the > arguments right, so the implementation is proc-based. > - removed the 'as {resultsVar optionsVar}' clause and introduced > per-handler variable assignment > - improved error messages > - improved behavior of '-during' > - added tests (there are just under 100 tests covering most aspects > of the functionality; more to come) > > Outstanding issues: > - In the case of a fallthrough body "-", to which variable(s) should > the outcome of the try body be assigned? Simplest solution: revert the decision about 'as {resultsVar optionsVar}' in the first place. Per-handler variables are redundant and add unnecessary complexity. Just set them once, they'll be available to all handler bodies, and the rest of the script from this point onwards, as anyone would expect. Simple, no surprised, no corner cases, and insanely efficient, plus forward-compatible if we ever get more useful handler matching. -- Fredderic The cost of living is going up and the chance of living is going down. -- Flip Wilson Debian/unstable (LC#384816) on i686 2.6.23-z2 2007 (up 11 days, 4:16) |