You can subscribe to this list here.
| 2000 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(19) |
Jul
(96) |
Aug
(144) |
Sep
(222) |
Oct
(496) |
Nov
(171) |
Dec
(6) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2001 |
Jan
(4) |
Feb
(4) |
Mar
(9) |
Apr
(4) |
May
(12) |
Jun
(6) |
Jul
|
Aug
|
Sep
(1) |
Oct
(2) |
Nov
|
Dec
|
| 2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
(52) |
Aug
(47) |
Sep
(47) |
Oct
(95) |
Nov
(56) |
Dec
(34) |
| 2003 |
Jan
(99) |
Feb
(116) |
Mar
(125) |
Apr
(99) |
May
(123) |
Jun
(69) |
Jul
(110) |
Aug
(130) |
Sep
(289) |
Oct
(211) |
Nov
(98) |
Dec
(140) |
| 2004 |
Jan
(85) |
Feb
(87) |
Mar
(342) |
Apr
(125) |
May
(101) |
Jun
(60) |
Jul
(151) |
Aug
(118) |
Sep
(162) |
Oct
(117) |
Nov
(125) |
Dec
(95) |
| 2005 |
Jan
(141) |
Feb
(54) |
Mar
(79) |
Apr
(83) |
May
(74) |
Jun
(125) |
Jul
(63) |
Aug
(89) |
Sep
(130) |
Oct
(89) |
Nov
(34) |
Dec
(39) |
| 2006 |
Jan
(98) |
Feb
(62) |
Mar
(56) |
Apr
(94) |
May
(169) |
Jun
(41) |
Jul
(34) |
Aug
(35) |
Sep
(132) |
Oct
(722) |
Nov
(381) |
Dec
(36) |
| 2007 |
Jan
(34) |
Feb
(174) |
Mar
(15) |
Apr
(35) |
May
(74) |
Jun
(15) |
Jul
(8) |
Aug
(18) |
Sep
(39) |
Oct
(125) |
Nov
(89) |
Dec
(129) |
| 2008 |
Jan
(176) |
Feb
(91) |
Mar
(69) |
Apr
(178) |
May
(310) |
Jun
(434) |
Jul
(171) |
Aug
(73) |
Sep
(187) |
Oct
(132) |
Nov
(259) |
Dec
(292) |
| 2009 |
Jan
(27) |
Feb
(54) |
Mar
(35) |
Apr
(54) |
May
(93) |
Jun
(10) |
Jul
(36) |
Aug
(36) |
Sep
(93) |
Oct
(52) |
Nov
(45) |
Dec
(74) |
| 2010 |
Jan
(20) |
Feb
(120) |
Mar
(165) |
Apr
(101) |
May
(56) |
Jun
(12) |
Jul
(73) |
Aug
(306) |
Sep
(154) |
Oct
(82) |
Nov
(63) |
Dec
(42) |
| 2011 |
Jan
(176) |
Feb
(86) |
Mar
(199) |
Apr
(86) |
May
(237) |
Jun
(50) |
Jul
(26) |
Aug
(56) |
Sep
(42) |
Oct
(62) |
Nov
(62) |
Dec
(52) |
| 2012 |
Jan
(35) |
Feb
(33) |
Mar
(128) |
Apr
(152) |
May
(133) |
Jun
(21) |
Jul
(74) |
Aug
(423) |
Sep
(165) |
Oct
(129) |
Nov
(387) |
Dec
(276) |
| 2013 |
Jan
(105) |
Feb
(30) |
Mar
(130) |
Apr
(42) |
May
(60) |
Jun
(79) |
Jul
(101) |
Aug
(46) |
Sep
(81) |
Oct
(14) |
Nov
(43) |
Dec
(4) |
| 2014 |
Jan
(25) |
Feb
(32) |
Mar
(30) |
Apr
(80) |
May
(42) |
Jun
(23) |
Jul
(68) |
Aug
(127) |
Sep
(112) |
Oct
(72) |
Nov
(29) |
Dec
(69) |
| 2015 |
Jan
(35) |
Feb
(49) |
Mar
(95) |
Apr
(10) |
May
(70) |
Jun
(64) |
Jul
(93) |
Aug
(85) |
Sep
(43) |
Oct
(38) |
Nov
(124) |
Dec
(29) |
| 2016 |
Jan
(253) |
Feb
(181) |
Mar
(132) |
Apr
(419) |
May
(68) |
Jun
(90) |
Jul
(52) |
Aug
(142) |
Sep
(131) |
Oct
(80) |
Nov
(84) |
Dec
(192) |
| 2017 |
Jan
(329) |
Feb
(842) |
Mar
(248) |
Apr
(85) |
May
(247) |
Jun
(186) |
Jul
(37) |
Aug
(73) |
Sep
(98) |
Oct
(108) |
Nov
(143) |
Dec
(143) |
| 2018 |
Jan
(155) |
Feb
(139) |
Mar
(72) |
Apr
(112) |
May
(82) |
Jun
(119) |
Jul
(24) |
Aug
(33) |
Sep
(179) |
Oct
(295) |
Nov
(111) |
Dec
(34) |
| 2019 |
Jan
(20) |
Feb
(29) |
Mar
(49) |
Apr
(89) |
May
(185) |
Jun
(131) |
Jul
(9) |
Aug
(59) |
Sep
(30) |
Oct
(44) |
Nov
(118) |
Dec
(53) |
| 2020 |
Jan
(70) |
Feb
(108) |
Mar
(50) |
Apr
(9) |
May
(70) |
Jun
(24) |
Jul
(103) |
Aug
(82) |
Sep
(132) |
Oct
(119) |
Nov
(174) |
Dec
(169) |
| 2021 |
Jan
(75) |
Feb
(51) |
Mar
(76) |
Apr
(73) |
May
(53) |
Jun
(120) |
Jul
(114) |
Aug
(73) |
Sep
(70) |
Oct
(18) |
Nov
(26) |
Dec
|
| 2022 |
Jan
(26) |
Feb
(63) |
Mar
(64) |
Apr
(64) |
May
(48) |
Jun
(74) |
Jul
(129) |
Aug
(106) |
Sep
(238) |
Oct
(169) |
Nov
(149) |
Dec
(111) |
| 2023 |
Jan
(110) |
Feb
(47) |
Mar
(82) |
Apr
(106) |
May
(168) |
Jun
(101) |
Jul
(155) |
Aug
(35) |
Sep
(51) |
Oct
(55) |
Nov
(134) |
Dec
(202) |
| 2024 |
Jan
(103) |
Feb
(129) |
Mar
(154) |
Apr
(89) |
May
(60) |
Jun
(162) |
Jul
(201) |
Aug
(61) |
Sep
(167) |
Oct
(111) |
Nov
(133) |
Dec
(141) |
| 2025 |
Jan
(122) |
Feb
(88) |
Mar
(106) |
Apr
(113) |
May
(203) |
Jun
(185) |
Jul
(124) |
Aug
(202) |
Sep
(176) |
Oct
(182) |
Nov
|
Dec
|
|
From: Joe M. <jo...@mi...> - 2008-11-21 21:49:10
|
>> TIP #335: An API for Detecting Active Interpreters
>
> I thought this was going to be amended to specify
> Tcl_IsInterpActive() instead of Tcl_GetNumLevels().
> The title of the TIP changed, but not the specification?
>
It is being changed; however, I did not realize it was going to
be voted on today.
The TIP cannot be changed while it is being voted on?
Anyhow, it will read:
~ Specification
This TIP introduces a single function to Tcl's public API:
> int '''Tcl_InterpActive'''(Tcl_Interp *''interp'')
The '''Tcl_InterpActive''' function returns non-zero if the interpreter is
in use.
~ Reference Implementation
|/*
| *----------------------------------------------------------------------
| *
| * Tcl_InterpActive --
| *
| * Returns non-zero if the specified interpreter is in use.
| *
| * Results:
| * See above.
| *
| * Side effects:
| * None.
| *
| *----------------------------------------------------------------------
| */
|
|int
|Tcl_InterpActive(Tcl_Interp *interp)
|{
| return (((Interp *) interp)->numLevels > 0);
|}
--
Joe Mistachkin <jo...@mi...>
|
|
From: Joe E. <jen...@fl...> - 2008-11-21 18:47:39
|
Donal K. Fellows wrote: > TIP #210: Add 'tempname' Subcommand to 'file' TIP#210: YES. > TIP #307: Make TclTransferResult() Public > TIP #337: Make TclBackgroundException() Public > TIP #338: Embedder Access to Startup Scripts of *_Main() TIP #307: YES. TIP #337: YES. TIP #338: YES. Useful stuff from the private interface that deserves to be public. > TIP #336: Supported Access To interp->errorline TIP #336: YES. Opaque Tcl_Interp *s at last! > TIP #306: Auto-Naming Widgets TIP#306: NO. This one does not play nicely with third-party widget sets or with megawidget packages. For the former, it places additional constraints on widget constructors. I have no idea how it will interact with the latter, though I suspect the answer is "not very well". I did a quick spot-check: with the proposed patch, tktable and the tile widgets automagically start supporting autonaming -- but only by accident -- while canvas3d, all BLT widgets, and tkhtml will break in new and exciting ways if you try to use the autonaming feature. I don't believe the proposed feature -- a minor convenience that only works some of the time -- is worth adding. > TIP #284: New 'invoke' and 'namespace invoke' Commands TIP#284: SEND IT BACK. I don't think this one got the API right, and it doesn't appear to add any new functionality. If "SEND IT BACK" is not a legal vote, then: TIP#284: NO. I need to think about these some more: > TIP #335: An API for Detecting Active Interpreters I thought this was going to be amended to specify Tcl_IsInterpActive() instead of Tcl_GetNumLevels(). The title of the TIP changed, but not the specification? TIP#335: TENTATIVE NO. If it's amended to specify Tcl_IsInterpActive() or something similar, then YES. > TIP #171: Change Default <MouseWheel> Bindings Behavior Definitely need to look at this some more. It just doesn't smell right to me. One thing in particular: instead of going through all sorts of rigamarole at the scripting level to redirect MouseWheel events to the widget under the pointer on Windows, wouldn't it make more sense to simply not redirect them to the focus window in the first place (see tkEvent.c, InvokeFocusHandlers)? That's how it's currently done on OSX. I suspect it also interferes with some of the ttk::* widgets. > TIP #197: Text Widget Persistant Cursor > TIP #238: Fire Event when Widget Created Don't know yet. --Joe English jen...@fl... |
|
From: <dg...@ni...> - 2008-11-21 18:26:04
|
Quoting "Kevin Kenny" <ke...@ac...>:
> The commonest case is filesystem errors, where presenting
> the OS status ("file not found", "no permission", "I/O
> error", etc.) appropriately translated makes sense. Right
> now, that's incredibly hard; you have to parse the error
> message and write a new one.
I agree with your reasoning, but you've chosen bad examples.
I/O errors are some of the few that actually set meaningful
-errorcode values:
% catch {open no-such} m o
1
% dict get $o -errorcode
POSIX ENOENT {no such file or directory}
DGP
|
|
From: <dg...@ni...> - 2008-11-21 18:16:29
|
Quoting "Jan Nijtmans" <nij...@us...>: > Some small remark about TIP #338 (there is no patch submitted, ... Just for the record, the patch isn't submitted yet since I haven't yet set aside time to puzzle out the thread-safety issues. If done wrong, exposure of these routines will lead to a repeat of Tcl Bug 801429. DGP |
|
From: Magentus <mag...@gm...> - 2008-11-21 17:37:02
|
On Thu, 20 Nov 2008 12:51:12 +0200,
Twylite <tw...@cr...> wrote:
The [finally script] usage is trivial to implement using unset traces
(although not quite as clean, mostly since it uses a magic variable
name).
proc finally {script {varName --finally--trap--}} {
upvar 1 $varName var
trace add variable var unset [list apply [list args $script]]
} ;# or something to that effect...
The [try] command for matching on something other than the return code
is excellent. Especially if it can match on return values as well as
errorcodes. How about this for a twist on the idea...
try {
script
} catch {
var ?opts?
} then {
script
} handler .....and so on.....
It's a bit freaky, with one or two variable names being where a script
chunk should be, but solves the question of where to put the return
string and option variables. Alternatively [try ?-vars ...? ....] or
something.
Regardless, why not have the handler clause evaluate an expression in
the context of a [dict with $opts]? Then you can use whatever matching
function you wish, the only minor pain is that you have to use some
ugly bracketing of the option names { ${-code} == 2 }. But maybe
there's a way around that, too, especially if the [dict with] is
doable read-only and non-destructively somehow.
And finally for over-all syntax, what'd be wrong with tagging the
try clauses onto the end of the present [catch] command. Make the
options variable mandatory in this usage, and bring it into scope for
the evaluations as above.
Just one of my warped out there thoughts (assuming someone hasn't
suggested the very same thing on the next yet-to-be-read message...
And if they have, count this as a vote for that! ;) ).
--
Fredderic
Debian/unstable (LC#384816) on i686 2.6.23-z2 2007 (up 44 days, 11:43)
|
|
From: Jan N. <nij...@us...> - 2008-11-21 16:55:19
|
2008/11/21 Donal K. Fellows <don...@ma...>:
> This is a Call For Votes on the following "small and practical" TIPs
> that I identified from my message earlier this week. (The other ones are
> in the process of being baked more.)
I cannot find a reason to reject any of those..... so:
TIP #171: YES
TIP #197: YES
TIP #210: YES
TIP #238: YES
TIP #284: YES
TIP #306: YES
TIP #307: YES
TIP #335: YES
TIP #336: YES
TIP #337: YES
TIP #338: YES
Some small remark about TIP #338 (there is no patch submitted, so I just
mention it here........)
> There will need to be some care taken for existing users of these routines via
> the private stubs table. The ability to compile against Tcl 8.6 headers, yet
> run against a pre-8.6 stubs table will likely be lost.
I think that problem can be prevented by changing genStubs.tcl.
currently we generate:
#ifndef Tcl_SetStartupScript
#define Tcl_SetStartupScript \
(tclIntStubsPtr->tcl_SetStartupScript) /* 178 */
#endif
change that to:
#undef Tcl_SetStartupScript
#define Tcl_SetStartupScript \
(tclIntStubsPtr->tcl_SetStartupScript) /* 178 */
Then we have this feature for all such functions.
Then, if someone somehow includes tclInt.h, the version in the
private stub table will be taken, otherwise the one in the public stub
table. Source compatibility restored :-)
Regards,
Jan Nijtmans
|
|
From: Donal K. F. <don...@ma...> - 2008-11-21 16:05:38
|
This is a Call For Votes on the following "small and practical" TIPs that I identified from my message earlier this week. (The other ones are in the process of being baked more.) TIP #171: Change Default <MouseWheel> Bindings Behavior TIP #197: Text Widget Persistant Cursor TIP #210: Add 'tempname' Subcommand to 'file' TIP #238: Fire Event when Widget Created TIP #284: New 'invoke' and 'namespace invoke' Commands TIP #306: Auto-Naming Widgets TIP #307: Make TclTransferResult() Public TIP #335: An API for Detecting Active Interpreters TIP #336: Supported Access To interp->errorline TIP #337: Make TclBackgroundException() Public TIP #338: Embedder Access to Startup Scripts of *_Main() Please send your votes to the tcl-core mailing list by 12:00 GMT next Friday (i.e. [clock format 1227873600]). My votes follow: TIP #171: YES TIP #197: YES TIP #210: YES TIP #238: YES TIP #284: YES TIP #306: YES TIP #307: YES TIP #335: YES TIP #336: YES TIP #337: YES TIP #338: YES Donal. |
|
From: Kevin K. <ke...@ac...> - 2008-11-21 13:17:40
|
Joe English wrote:
> Some anecdotal evidence, FWIW: reviewing some old code I
> came across two places where I was initially tempted
> to use meaningful -errorcodes, but then thought
> "Why bother? I'm never going to look at them,
> the [if {[catch { }]} { switch $::errorCode { ... } }]
> idiom is utterly unperspicuous," so I didn't.
> Had a nice try/onerror construct been available,
> I would have. So I don't think the hypothesis
> is entirely without merit :-) Sure, it's only
> a reduction of about 1 line of code, but that 1
> line is *ugly* code.
I think it might be informative to separate the discussion
of "meaningful errorcodes" from try/catch/finally, because
I want meaningful errorcodes for an entirely different reason.
For error messages that are likely to reach an application's
user, there is likely to be a desire for localisation.
The commonest case is filesystem errors, where presenting
the OS status ("file not found", "no permission", "I/O
error", etc.) appropriately translated makes sense. Right
now, that's incredibly hard; you have to parse the error
message and write a new one. It would be nice to have
at least *some* error codes that can hook into msgcat
gracefully.
--
73 de ke9tv/2, Kevin
|
|
From: Jan N. <nij...@us...> - 2008-11-20 22:53:34
|
2008/11/20 Andreas Leitgeb <av...@lo...>: > "Jan Nijtmans" <nij...@us...> wrote: >> The patch for TIP #340 is available now, and the description of the >> TIP is updated: >> http://sourceforge.net/tracker/index.php?func=detail&aid=2315890&group_id=10894&atid=310894 > > I think a mention of Tcl_SetObjResult (or other alternatives) should > be added to the Deprecation-block. One could argue that the referral > to the TIP covers it, but I still think it would be a good thing to > have that piece of information immediately at hand without having to > look up the TIP. Agreed, will do that. However, even after the TIP voting, improving documentation is always a good thing. Thanks! Regards, Jan Nijtmans |
|
From: Twylite <tw...@cr...> - 2008-11-20 22:14:14
|
Hi,
> It's not a range - the "-" in switch means "use the same body as the
> next branch". i.e., the example means codes 0 and 4 (ok and continue),
> not 0 to 4.
Ah. My bad. A violation of rule #2: never engage in a debate when the
coffee has run out.
I had been thinking about catching ranges of return codes (e.g. all
user-defined codes as opposed to Tcl-reserved codes) and wasn't paying
enough attention to the code.
> OK. On reflection I'm willing to concede that adequate error case
> analysis requires pattern matching of some sort built-in to [try].
Yay :)
>> Of course its entirely possible that some bright spark declares that if
>> the general class of errorCode is "OBJECT" then [lindex $errorCode 1] is
>> an oo::object that is a child of tcl::errorobj, and you want to do
>> class-based matching on said object. This is probably quite a strong
>> argument against glob matching (as the only option).
> Good point. I hadn't thought of that. That also could handle
> subtype-based matching.
>> So I have been suggesting "string match" on a structured list as an
>> approximation of the 'isa' / 'typeof' operator.
> Which could be workable: the OO exception just dumps [$self info
> ancestors] or whatever into the errorCode, so you have something like:
> [list Error IOError HostUnreachable object12].
That certainly has the potential to work. Constructing the error object
(or calling [errorobj throw]) - however you want it to work - would do a
[return -options {...}] putting the object into the options dict, but
also [$self info ancestors] into -errorcode.
>> My point here applies most specifically to cases where you don't control
>> the API (which is rather common), but also to cases where you don't want
>> to modify the API - because it will affect other working code that you
>> don't want to refactor, or because you believe that adding a flow
>> control statement like 'break' or 'continue' outside of a flow control
>> construct is an inherently dangerous code practice because developers
>> using APIs don't expect stuff like that.
> Well, all exceptions affect flow control.
I humbly submit that while one can do immensely cool things with Tcl,
the average developer (indeed, a good number of well-above-average
developers) will adopt the WTF face when confronted with the idea that a
procedure can throw a continue. We live in the Victorianesque era of
structure code, and one simply does not abide by such vulgarity in
civilised society.
>>> proc connect {schemes host user pass} {
>>> foreach scheme $schemes {
>>> try {
>>> return [$scheme connect $host $user $pass]
>>> } on error BADAUTH {} { continue }
>>> }
>>> error "unable to authenticate"
>>> }
> I agree that errorcode is pretty unlikely to be useful outside of
> errors, hence making it optional. I still quite like the symmetry of
> this proposal.
The symmetry is attractive, but I can't help feeling that if we are
trying to shoehorn exception handling and error handling into the same
construct then a reasonable amount of asymmetry is expected. In fact a
clear distinction between handling errors and handling exceptions may
make the intent of the code more evident.
>> Matching:
>> c. Possibly provide for more complex matches involving other fields
>> (result), regular expressions, disjunctive matching, case sensitivity,
>> relational calculus/algebra, whatever.
> Ha! Maybe subsumption based matching using a description logic
> reasoner? :-)
.. strange ... I though Girl Genius was in the other tab.
> It seems clear that matching on a the return code (or a list of) can
> be done in O(1). It seems we agree that this can and should be
> supported. How much to support narrowing down beyond that is the main
> focus of debate. I'm prepared to agree with you that some sort of
> errorCode matching would be beneficial. Glob-matching errorCode is
> reasonably cheap and probably does cover most common cases. Another
> cheap alternative would be to treat the pattern as simply a list of
> constants and then match by finding longest common prefix between the
> matches and the errorcode, which would have worst case O(N) where N is
> the llength of $errorCode. That also has the advantage that you can
> compile all catch blocks into a single pattern matching tree
> (trie-like). While customised pattern matching is appealing, it seems
> likely to involve extra complexity in both usage and implementation,
> with probably performance impacts too. User-supplied predicates or
> customisable pattern matching is likely to be much less efficient, so
> should probably not be the default.
Mmm ... the performance vs flexibility trade-off. The compromise is
usually to allow the user to select which they need for the particular
case. This one deserves more thought, possibly at a less reasonable
hour (like in the morning).
>> try {
>> # ...
>> } thenwith -glob -- "%C,%E" {
>> "1,POSIX *" { handle posix errors }
>> "3,*" -
>> "4,*" { handle break/continue }
>> }
> I don't think it matters whether [try] delegates to [switch] in the
> implementation. This still results in [try] acquiring the interface of
> [switch].
True, but also the full functionality of switch, and any enhancements
made to switch. Matching is not limited to a particular approach that
I/we think is appropriate right now, but has the flexibility to address
a wide range of needs.
>> (2) Make [try] an unholy union of [catch] and [if]/then/else, and
>> provide helper functions/operations to match exception/error cases with
>> expr.
>> try {
>> # ...
>> } handle { [string match "POSIX *" $::errorCode] } {
>> handle posix errors
>> }
> I briefly considered something along those lines -- general predicates
> as guards. I think it's getting too complex though. As you say, [try]
> doesn't need to handle all cases -- it just needs to handle the most
> common cases decently.
Oh, to have a convenient and provably accurate definition of "common
cases" ;)
> Just ignore me and go with glob-matching or prefix matching. So long
> as non-error exceptions are handled well, I'll be happy.
I'd prefer not to -- your approach is often different to mine and it
pays to consider all views and comments when designing a feature like
this. I had already started breaking down the separate concerns, look &
feel and matching options before this particular thread started, and
noted that expr matching provides the more flexible and potentially most
consistent [try] command, but is somewhat ugly around the actual match.
I had been letting this stew for a bit (paid-work time pressures) but it
looks like decisions need to be taken soon. Still, I prefer to take a
good look at all angles of a problem before taking decisions that become
permanent.
Regards,
Twylite
|
|
From: Michael S. <sc...@un...> - 2008-11-20 20:16:26
|
Am 20.11.2008 um 19:18 schrieb Joe English:
> Some anecdotal evidence, FWIW: reviewing some old code I
> came across two places where I was initially tempted
> to use meaningful -errorcodes, but then thought
> "Why bother? I'm never going to look at them,
> the [if {[catch { }]} { switch $::errorCode { ... } }]
> idiom is utterly unperspicuous," so I didn't.
Grepping inside Tcllib also shows rather weak usage of -errorcode.
Some of the network protocols (LDAP, SPF), ASN, wip, some math
subpackages, comm.
Michael
|
|
From: David G. <dav...@po...> - 2008-11-20 19:38:26
|
Donal K. Fellows wrote: > Remember, the broad strategy is to keep Tcl 8.6 on track for a Spring > 2009 final release. We took far too long with both 8.4 and 8.5... Well, then IPv6 won't hit for 8.6 then... I work a real job, too :) There is just too much work to do in FIXING the broken stuff BEFORE adding new functionality. I haven't even brought up QoS yet. 1) [socket -async foo.example.com 1234] blocks on DNS rather than being async as requested. 2) proper DNS errors are lost. 3) WinSock code is in dire need of a revamp to a decade ago's methodologies. 4) Tcl_OpenTcp(Client|Server) both take an int value for the port values instead of a string. This places a network protocol understanding requirement into the generic code to resolve port names (generic/tclIOSock.c). Not a big deal really, but I'd like to see either the signatures change, or a new level of indirection so that protocol specifics don't have be in the generic side of Tcl_SocketCmd(). True, the BSD socket call getservbyname() is consistent across platforms, and was probably the reason why Scott Stanton put it there, but there was extra work on the windows side through C macros to allow it to go through the winSockProcs function table (now removed by Pat Thoyts). But a larger issue exists here that restricts Tcl_SocketCmd from being the general entry for all network stream creation and even resolution. Some network protocols use a tuple arrangement like IPX and AppleTalk, but I don't really see a problem combining network and node into the one address string. 5) What's up with UDP and message based channels? |
|
From: Neil M. <ne...@Cs...> - 2008-11-20 19:11:24
|
On 20 Nov 2008, at 16:39, Twylite wrote:
>> [...]
[on finally:]
>> I'd be happy to see this part of the TIP dropped or separated into a
>> different command however.
> I wouldn't be particularly happy to drop/separate this functionality.
My thought here was merely that a decision on "finally" could be
separated from considerations of try/catch. I.e., it could form a
separate TIP, either extending [try] or adding a separate capability
like your [finally] command or some [ensure] command or something.
Just an idea though -- I think "finally" as part of try is a well
established convention and fairly uncontroversial.
> Doing so will result in more deeply nested code, because the need for
> cleanup regularly interacts with the need to handle (some)
> errors/exceptions (rather than let them all propagate).
> Also, there are three orthogonal concerns, all wanting to be called
> "try", which will just get messy.
>
> My proposal (or at least implementation, I forget) chains errors to
> the
> original in all cases (i.e. if you throw an error from a handler or
> from
> finally).
OK, good.
>> 2. Case-analysis based on return code
>> An example here is that of implementing custom control structures. Of
>> particular interest here is the use of standard exceptions like
>> [break] and [continue]. For instance, we may want to write a version
>> of [foreach] that operates asynchronously using the event loop.
>> Currently, we might write this as:
>> The try/handle (Twylite/JE) alternative would be:
>>
>> } handle {code msg opts} {
>> switch $code {
>> 3 { return }
>> 0 - 4 { # ok/continue }
>> default { return -options $opts $msg }
>> }
>> }
> Umm ... no. JE said:
>> } handle {code ?resultVar ?optionsVar??} {
>> #
>> # return code was $code.
>> #
>> } finally {
>>
>> where "code" is one of ok/error/return/break/continue
>> or an integer literal, a la [return -code].
>>
> So the use would be
> } handle {2 msg opts} {
> # handle the case where the return code is 2 (TCL_RETURN)
> } handle {1 msg opts} {
> # handle the case where the return code is 1 (TCL_ERROR)
> }
> etc. And you can use the keywords ok/error/return/break/continue
> instead of the integer literals.
OK. The comment "return code was $code" made me think that "code" was
a variable, rather than a pattern.
>
> On http://wiki.tcl.tk/21608 I proposed using the keyword 'except' and
> matching on 'spec' which I hadn't defined, but was tentatively
> assuming
> to be the return code.
>
> In other words, our proposal is the same as the try/catch example you
> present.
Great. In that case, I think we're largely in agreement.
>> proc async-foreach {varName list body} {
>> if {[llength $list] == 0} { return }
>> set list [lassign $list item]
>> try {
>> apply [list $varName $body] $item
>> } catch break {} { return } catch continue {} {}
>> after 0 [list async-foreach $varName $list $body]
>> }
> The difference is that you use
> catch on_what_code {?emvar? ?optsvar?} ?body?
> and we use
> handle {on_what_code ?emvar? ?optsvar?} ?body?
>> Note that dispatch based on exception code is a simple branch. There
>> is no need for complex pattern matching, sub-match capture, or
>> case-insensitive matching.
> Mmm ... except you cheat in your example ;)
> In the examples using [switch] you use a range (0 - 4), which try/
> catch
> doesn't handle. And you put all the cases on one line ;p
It's not a range - the "-" in switch means "use the same body as the
next branch". i.e., the example means codes 0 and 4 (ok and
continue), not 0 to 4.
> [...]
> It seems to me that the [try] must not dictate/limit the matching, but
> must facilitate it.
> The problem with catch+switch and similar approaches is that they are
> _ugly_. Your try/catch suggestion is no more powerful than
> catch+switch, but it is more readable. When you scan the code you see
> "try ... catch", and the intention of the code is clear. When you see
> "catch ... switch" the intention is not clear -- you have no idea that
> these two statements are related, and if they are then on what
> basis are
> you switching, etc.
>
> If one accepts that Tcl return codes should be used for flow control,
> and that the Tcl return code 1 (TCL_ERROR) covers all errors (which
> are
> called structured exceptions in languages like C++ and Java), and that
> there is a need to distinguish between different structured exceptions
> (Tcl errors) based on their cause/type/class/nature (whatever you want
> to call it), then the inescapable conclusion is that there needs to
> be a
> not-ugly control structure to handle branching based on return
> code, and
> a not-ugly control structure to handle branching based on error cause.
> They may or may not be the same control structure, but they are both
> equally necessary.
OK. On reflection I'm willing to concede that adequate error case
analysis requires pattern matching of some sort built-in to [try].
>> Perhaps I am wrong here, and glob-matching meets all requirements.
> Maybe, maybe not. I'm honestly not sure either way. Assuming that
> errorCode is constructed in a hierarchical manner (most general class
> first, becoming progressively more specific) then I can't think of a
> situation that a glob match can't handle (where an equivalent
> situation
> exists in say Java or C++ that can be handled by their syntax).
> Of course its entirely possible that some bright spark declares
> that if
> the general class of errorCode is "OBJECT" then [lindex $errorCode
> 1] is
> an oo::object that is a child of tcl::errorobj, and you want to do
> class-based matching on said object. This is probably quite a strong
> argument against glob matching (as the only option).
Good point. I hadn't thought of that. That also could handle subtype-
based matching.
>> Personally, if errorcode matching was to take off, I would use some
>> form of algebraic types (tagged lists) both for constructing and
>> pattern-matching errorcodes, as that seems to me to be the most
>> appropriate tool for the job. Perhaps there is a way to keep the
>> behaviour but to parameterise the matching command (with switch
>> -glob/string match being the default).
> Yes, there is, maybe. More below.
>> The other question is whether these cases arise in practice. I can't
>> think of a single existing API that requires this kind of errorcode
>> pattern matching. Is such a design even appropriate? Clearly, if you
>> controlled the authentication scheme interface then you could just
>> return continue for BADAUTH and an error for anything else:
> Depending on your understanding of "pattern matching" ... Java. Like
> the whole Java Runtime Library.
> Java obviously doesn't use globs to match exceptions, but it does
> throw
> different exceptions and you can catch a group of exceptions based
> on a
> pattern (specifically: the exception object is of a particular class).
> errorCode is defined as being a list where the first element
> identifies
> the general class of errors; assuming that this format is maintained
> (for legacy compatibility) the most obvious approach to asking "is
> this
> an IO error" is "IO *".
> So I have been suggesting "string match" on a structured list as an
> approximation of the 'isa' / 'typeof' operator.
Which could be workable: the OO exception just dumps [$self info
ancestors] or whatever into the errorCode, so you have something
like: [list Error IOError HostUnreachable object12].
> My point here applies most specifically to cases where you don't
> control
> the API (which is rather common), but also to cases where you don't
> want
> to modify the API - because it will affect other working code that you
> don't want to refactor, or because you believe that adding a flow
> control statement like 'break' or 'continue' outside of a flow control
> construct is an inherently dangerous code practice because developers
> using APIs don't expect stuff like that.
Well, all exceptions affect flow control.
> [...]
>> proc connect {schemes host user pass} {
>> foreach scheme $schemes {
>> try {
>> return [$scheme connect $host $user $pass]
>> } on error BADAUTH {} { continue }
>> }
>> error "unable to authenticate"
>> }
>> To me this seems like a good compromise, and people who want more
>> complex pattern matching can still do so. I'd like to be able to
>> support lists of exception types. I still don't believe glob-style
>> errorCode pattern matching is useful or particularly satisfactory,
>> but
>> I'm willing to concede it for the sake of compromise. As before,
>> define "then" as "on ok", and possibly define "else/otherwise" as a
>> catch-all default clause.
> It looks promising, but I doubt that errorCode is every really
> meaningful outside the context of TCL_ERROR, and I'm leaning towards
> glob being insufficient as the only supported matching style. It's
> all
> your fault for being right ;p
:-) Sorry!
I agree that errorcode is pretty unlikely to be useful outside of
errors, hence making it optional. I still quite like the symmetry of
this proposal.
>> <aside>
>> I also see this meshing nicely with a hypothetical future
>> continuation-based exception mechanism that allows
>> resumable/non-destructive exception/warning notifications.
>> </aside>
> I've been glimpsing some opportunities here, but I don't work with CPS
> enough to have a good idea of how to work it in.
It's a nice vision, but not workable within a 8.x timeframe. To
really work, it would require changing the way C code reports
exceptions (e.g., calling some Tcl_Throw rather than returning an
error code). With the NRE changes though, this kind of thing begins
to look more feasible though.
>>> On supporting widely-used idioms, it would be much more important
>>> IMO
>>> to branch based on the result than on the return code. Branching
>>> based on return code (i.e. exception handling) is useful for
>>> creating
>>> new control structures, but if you want to handle errors then you
>>> must branch based on some information that is available from a
>>> return
>>> code = TCL_ERROR (2). That means either errorCode or result, and
>>> right now most APIs are using result.
>>> You make a good point about leaving pattern matching to existing
>>> commands -- I have been thinking along those lines for how best to
>>> exploit that (more in another mail).
>> Branching based on the result just seems like a fragile nightmare.
>> Localised error messages for instance could totally change the
>> behaviour of code.
> Oh, it is ;( But its also the only option available in some existing
> libraries. I've encountered code that puts an error identified in the
> result and the error message in errorInfo, for example.
> The question then is: how widespread is such (bad) code. Would
> developers regularly resort to another branching mechanism (try
> +switch,
> catch+switch, etc.) or would they be able to use the new [try] for the
> vast majority of their code?
I think in this case this is a common idiom we want to actively
discourage! :-)
>>> Let's drop to Java-speak for a moment: the current practice of Tcl
>>> developers is to "catch (Exception e) { // handle }". In C++ it is
>>> "catch (...) { // handle }".
>>> Return code is not a mechanism for exception/error typing, it is a
>>> mechanism for implementing control flows. We need a typing
>>> mechanism.
>> Hmmm... error handling needs case-analysis not typing per se.
>> Clearly,
>> any mechanism used for constructing error cases is strongly
>> related to
>> the mechanism that is used for distinguishing them, which is why I'd
>> rather see these aspects separated/parameterised from the exception
>> handling, at least until it is clear what the best mechanism for
>> this is.
> I'm going to take a stab at identifying what the best mechanism is.
>
> Let's move back for a moment to what we're trying to achieve here.
>
> Functionality:
> a. Handle errors by class (errorCode)
> b. Handle success continuation (i.e. don't limit the control
> structure
> to only exceptional situations)
> c. Handle other (non-error) exceptions
> d. It is clear that (a), (b) and (c) are all specialisations of
> matching the Tcl return code (and possibly some other return
> information, like errorCode and result)
> e. Clean up at the end of an operation, regardless of errors/
> exceptions
>
> Look & Feel:
> a. Looks like if/then/else (traditional structured try/catch as in
> C++, Java, etc), OR
> b. Looks like switch (I don't actually know of another language that
> does this), OR
> c. Hybrid of (a) and (b): choose between success/error with an
> if/then/else like construct, then switch on the specific result/error
> (e.g. Erlang)
>
> Matching:
> a. Match a single return code, a range of return codes, or a
> discrete
> list of return codes
> b. Match a specific error code, and an errorcode pattern (glob-like)
> c. Possibly provide for more complex matches involving other fields
> (result), regular expressions, disjunctive matching, case sensitivity,
> relational calculus/algebra, whatever.
Ha! Maybe subsumption based matching using a description logic
reasoner? :-)
It seems clear that matching on a the return code (or a list of) can
be done in O(1). It seems we agree that this can and should be
supported. How much to support narrowing down beyond that is the main
focus of debate. I'm prepared to agree with you that some sort of
errorCode matching would be beneficial. Glob-matching errorCode is
reasonably cheap and probably does cover most common cases. Another
cheap alternative would be to treat the pattern as simply a list of
constants and then match by finding longest common prefix between the
matches and the errorcode, which would have worst case O(N) where N
is the llength of $errorCode. That also has the advantage that you
can compile all catch blocks into a single pattern matching tree
(trie-like). While customised pattern matching is appealing, it seems
likely to involve extra complexity in both usage and implementation,
with probably performance impacts too. User-supplied predicates or
customisable pattern matching is likely to be much less efficient, so
should probably not be the default.
>
> catch+something_else can provide for arbitrary complexity. Should
> [try]
> also do so, or should its complexity be limited? If limited, what
> is a
> reasonable limit? Exact match? Range match? Glob match?
>
> It strikes me that there are two possible solutions:
>
> (1) Make [try] an unholy union of [catch] and [switch] such that the
> user can specify the information being switched on (e.g. "%C,%E,%R"
> where %C is the return code, %E is the errorcode and %R is the
> result).
> You delegate pattern matching to [switch] and allow the user to match
> based on any combination of return code, errorcode and result.
>
> try {
> # ...
> } thenwith -glob -- "%C,%E" {
> "1,POSIX *" { handle posix errors }
> "3,*" -
> "4,*" { handle break/continue }
> }
I don't think it matters whether [try] delegates to [switch] in the
implementation. This still results in [try] acquiring the interface
of [switch].
>
> (2) Make [try] an unholy union of [catch] and [if]/then/else, and
> provide helper functions/operations to match exception/error cases
> with
> expr.
>
> try {
> # ...
> } handle { [string match "POSIX *" $::errorCode] } {
> handle posix errors
> } handle { code() in {3 4} } {
> handle continue
> }
>
> Asssuming some minor changes to expr that could look more like:
>
> try {
> # ...
> } handle { errorcode() like "POSIX *" } {
> } handle { code() in {3 4} } {
> }
>
> I found the question on Reddit at
> http://www.reddit.com/r/programming/comments/7dgwy/
> ask_proggit_where_clauses_in_catch_declarations/?sort=old
> quite interesting in this regard.
I briefly considered something along those lines -- general
predicates as guards. I think it's getting too complex though. As you
say, [try] doesn't need to handle all cases -- it just needs to
handle the most common cases decently. Just ignore me and go with
glob-matching or prefix matching. So long as non-error exceptions are
handled well, I'll be happy.
-- Neil
This message has been checked for viruses but the contents of an attachment
may still contain software viruses, which could damage your computer system:
you are advised to perform your own checks. Email communications with the
University of Nottingham may be monitored as permitted by UK legislation.
|
|
From: Joe E. <jen...@fl...> - 2008-11-20 18:39:30
|
Neil Madden wrote:
> The try/handle (Twylite/JE) alternative would be:
>
> proc async-foreach {varName list body} {
> if {[llength $list] == 0} { return }
> set list [lassign $list item]
> try {
> apply [list $varName $body] $item
> } handle {code msg opts} {
> switch $code {
> 3 { return }
> 0 - 4 { # ok/continue }
> default { return -options $opts $msg }
> }
> }
> after 0 [list async-foreach $varName $list $body]
> }
A clarification: this is not what I proposed in [1].
In a clause like:
handle {code ?resultVar ?optionsVar??} { script }
"code" would be an integer or a literal "ok"/"error"/etc.,
not a variable name. Same as the
catch code {?resultVar ?optionsVar??} { script }
form you proposed, just spelled slightly differently.
What I had in mind would look like:
try {
apply [list $varName $body] $item
} handle return {
return
} handle ok {
# no-op
} handle continue {
# no-op
}
The clause "default { return -options $opts $msg }" from
the first script is unneeded, since that's the default
behaviour of [try] when no "handle" or "onerror" clause
matches.
--Joe English
[1] <URL: http://sourceforge.net/mailarchive/message.php?msg_name=E1L2s55-0001xW-6L%40eurydice.office.flightlab.com >
|
|
From: Joe E. <jen...@fl...> - 2008-11-20 18:18:39
|
Twylite wrote:
>
> First up, I want to be clear about the intent behind TIP #329:
> a) The TIP is about error handling, not exception handling. Tcl has
> excellent exception handling which can be readily used in a mostly
> non-ugly way (e.g. catch + if/then/else or catch + switch),
[ FWIW, I don't fully agree. TIP#89 made correct exception
handling _possible_, but it's still not very convenient or pretty.
That's why I think it's essential that TIP#239 support exception
handling as well, not just error handling. Especially since it
can easily do so with only minor changes. ]
> but its error handling is poor.
Full agreement here.
> > I don't like the alternative approach [to try/finally] much either,
> > simply because it smells too much like innovation.
> >
> And there I was thinking that Tcl generally supported innovation ;p
Again: I think the alternative approach sounds interesting
and is worth pursuing, just *not in this TIP*, and *not right now*.
We have a short deadline for 8.6.
[Elsewhere]
Neil Madden wrote:
[ re: error handling ]
> I believe this is already addressed by the presence of errorCode.
> Pattern-matching against this code is already quite simple, with
> [switch] and so on. It just hasn't caught on. It seems like wishful
> thinking to expect that it will suddenly catch on just because its usage
> is made slightly more convenient (we're talking about a reduction of
> about 1 line of code).
Some anecdotal evidence, FWIW: reviewing some old code I
came across two places where I was initially tempted
to use meaningful -errorcodes, but then thought
"Why bother? I'm never going to look at them,
the [if {[catch { }]} { switch $::errorCode { ... } }]
idiom is utterly unperspicuous," so I didn't.
Had a nice try/onerror construct been available,
I would have. So I don't think the hypothesis
is entirely without merit :-) Sure, it's only
a reduction of about 1 line of code, but that 1
line is *ugly* code.
--Joe English
jen...@fl...
|
|
From: Joe E. <jen...@fl...> - 2008-11-20 17:49:12
|
Donal K. Fellows wrote: > >> TIP #210 Add 'tempname' Subcommand to 'file' > [...] > I've revised the TIP to swap those arguments as suggested. (While the > TIP previously allowed template to be blank, that was still messy and > non-obvious!) I've also made it much clearer what the template format > actually is, and I hope that someone can check that I've not messed it > up in the process. Assuming I've not blundered, it's now good to go. Thank you! The revised synopsis looks good -- exactly right in fact -- and fixes the other complaint (namely that the interpretation of $template was underspecified). Can we issue a CFV on this one? --JE |
|
From: Donal K. F. <don...@ma...> - 2008-11-20 16:41:10
|
Neil Madden wrote: > I believe this is already addressed by the presence of errorCode. > Pattern-matching against this code is already quite simple, with > [switch] and so on. It just hasn't caught on. It seems like wishful > thinking to expect that it will suddenly catch on just because its usage > is made slightly more convenient (we're talking about a reduction of > about 1 line of code). Also a reduction in the nesting depth. That reduces user-visible complexity. That's a good bonus. > 4. Trapping only those errors/exceptions you are interested in > -------------------------------------------------------------- > > It's clear from the above that the Twylite/JE approach achieves this for > errors, but not for other exceptions. My approach achieves it for > exceptions but not for more specific error cases. The problem with making more use of exception codes is that they're a global resource; they're not easy to restrict to a single interpreter. That makes them significantly less suitable for use in packages, and hence restricts their general applicability rather a lot. They've also got hard-coded traceability behaviour (i.e. none). > Branching based on the result just seems like a fragile nightmare. > Localised error messages for instance could totally change the behaviour > of code. Agreed. And localizing error messages is messy too without in effect the effort required to generate errorcodes properly. Which in turn makes the error trapping proposed viable and useful. :-) Donal. |
|
From: Twylite <tw...@cr...> - 2008-11-20 16:40:13
|
Awesome stuff Neil - thanks for the detailed analysis :)
>> Developers use the result (Tcl_SetResult, not return code) as an
>> error message, representing both the class/category and exact nature
>> of the error (in a human-readable form), but don't provide a way to
>> programatically identify the class of error making control flow based
>> on the type of error a hit-and-miss match on the error code.
> I believe this is already addressed by the presence of errorCode.
> Pattern-matching against this code is already quite simple, with
> [switch] and so on. It just hasn't caught on. It seems like wishful
> thinking to expect that it will suddenly catch on just because its
> usage is made slightly more convenient (we're talking about a
> reduction of about 1 line of code).
As you note, it hasn't caught on. I believe that is because (i) the
language feature to throw errors discourages (or at least does not
encourage) the use of errorCode, and (ii) there is no obvious feature to
branch based on errorCode. I intend to resolve that through this TIP by
making [try] support branching on errorCode, and [throw] reorder the
arguments of [error] to encourage the use of an errorCode.
> I think it is worth explicitly pulling out the separate concerns
> embodied in this TIP and tying them to use-cases. As I see it, there
> are a number of more-or-less separable concerns here:
>
> 1. Support for ensuring resource cleanup in the presence of
> exceptions/errors (i.e. "finally").
> 2. Better support for case-analysis based on exception return code.
> 3. Better support for case-analysis based on errorcode.
> 4. Ability to trap only those exceptions/errors that you are
> interested in/prepared to deal with, letting others propagate normally.
Most wicked - I had just made this list myself (well, the first 3 at
least). We have 3 orthogonal concerns here that we are trying to
shoehorn into one command.
> try { process $chan } finally { close $chan }
>
> This is a saving of two lines, but I think the improvement in
> readability is worth it. A possible improvement would be for any
> errors in the finally clause to not completely mask any errors in the
> main script -- perhaps by adding a -original field to the options dict
> (which itself contains the message and options dict of the original
> error).
>
> I'd be happy to see this part of the TIP dropped or separated into a
> different command however.
I wouldn't be particularly happy to drop/separate this functionality.
Doing so will result in more deeply nested code, because the need for
cleanup regularly interacts with the need to handle (some)
errors/exceptions (rather than let them all propagate).
Also, there are three orthogonal concerns, all wanting to be called
"try", which will just get messy.
My proposal (or at least implementation, I forget) chains errors to the
original in all cases (i.e. if you throw an error from a handler or from
finally).
> 2. Case-analysis based on return code
> An example here is that of implementing custom control structures. Of
> particular interest here is the use of standard exceptions like
> [break] and [continue]. For instance, we may want to write a version
> of [foreach] that operates asynchronously using the event loop.
> Currently, we might write this as:
> The try/handle (Twylite/JE) alternative would be:
>
> } handle {code msg opts} {
> switch $code {
> 3 { return }
> 0 - 4 { # ok/continue }
> default { return -options $opts $msg }
> }
> }
Umm ... no. JE said:
> } handle {code ?resultVar ?optionsVar??} {
> #
> # return code was $code.
> #
> } finally {
>
> where "code" is one of ok/error/return/break/continue
> or an integer literal, a la [return -code].
>
So the use would be
} handle {2 msg opts} {
# handle the case where the return code is 2 (TCL_RETURN)
} handle {1 msg opts} {
# handle the case where the return code is 1 (TCL_ERROR)
}
etc. And you can use the keywords ok/error/return/break/continue
instead of the integer literals.
On http://wiki.tcl.tk/21608 I proposed using the keyword 'except' and
matching on 'spec' which I hadn't defined, but was tentatively assuming
to be the return code.
In other words, our proposal is the same as the try/catch example you
present.
> proc async-foreach {varName list body} {
> if {[llength $list] == 0} { return }
> set list [lassign $list item]
> try {
> apply [list $varName $body] $item
> } catch break {} { return } catch continue {} {}
> after 0 [list async-foreach $varName $list $body]
> }
The difference is that you use
catch on_what_code {?emvar? ?optsvar?} ?body?
and we use
handle {on_what_code ?emvar? ?optsvar?} ?body?
> Note that dispatch based on exception code is a simple branch. There
> is no need for complex pattern matching, sub-match capture, or
> case-insensitive matching.
Mmm ... except you cheat in your example ;)
In the examples using [switch] you use a range (0 - 4), which try/catch
doesn't handle. And you put all the cases on one line ;p
IF a catch/handle can only match on exactly one return code, the
branching is simple. But you may want to match on a range.
Or even against a discrete list:
> The syntax of the catch part would be: catch "?exception-type? vars
> script", where exception-type is a non-empty *list* of "error",
> "continue", "break", "return", "ok", or numeric return codes. It
> defaults to "error".
> 3. Case-analysis based on errorcode
>
> For this, I'll use Twylite's example of trying different
> authentication schemes. We will assume that the API throws an error
> with code BADAUTH when the wrong scheme is used, and throws other
> errors such as NOCONN to indicate that a connection to the host
> failed. (Note: this example doesn't require glob-matching, but I don't
> think the changes in such a case are that great). The existing way to
> handle this would be:
man tclVars: " This list value represents additional information about
the error in a form that is easy to process with programs. The first
element of the list identifies a general class of errors, and determines
the format of the rest of the list."
You need to do pattern matching on errorCode, or select based on [lindex
$::errorCode 0] assuming that only the most general class information is
relevant.
> OK, in this case the try/onerror approach certainly is clearer, and
> the try/catch approach is little better than the existing way with
> [catch] alone. I think it still wins slightly over [catch] in
> readability. While it is more verbose, the control flow is easier to
> read -- the [return] is in an obvious place, and not tucked away in an
> inconspicuous "else" clause. There's also less punctuation. But the
> onerror approach is clearly better for this case.
Forgive me for leaving our the preceding 40 lines of example, and
focusing on this paragraph ;)
> The questions then, are whether "onerror" is sufficient for all/most
> such cases, and whether these cases actually arise often/ever in
> practice (or would arise given appropriate promotion). Regarding the
> first part, dispatching based on errorcode is more complex than based
> on return code as while the latter is a simple integer, the former can
> be an arbitrarily complex data structure. In particular, the following
> requirements may have to be considered:
>
> a. Different forms of pattern-matching (e.g. exact, glob, regexp,
> "algebraic" type matching etc). If we stick to one type only, will
> that be appropriate? Will it cause problems? (e.g. if glob-only
> matching, then we have problems specifying glob-special characters
> such as * or []).
> b. Case sensitivity -- is "arith" the same error as "ARITH" or "ARiTh"?
> c. Sub-match capture: an errorcode may contain detail fields which we
> want to extract. It seems pointless to match once and then perform a
> separate extraction when I could have just used [regexp] or some other
> matching facility and performed both operations in one go.
> d. Disjunctive matching: perform this action if the errorcode matches
> either *this* or *that*.
>
> I'm sure there are others. To me, the range of choices here suggests
> that pattern matching is best kept separate from error-handling.
> Otherwise there is a risk of duplicating [switch].
It seems to me that the [try] must not dictate/limit the matching, but
must facilitate it.
The problem with catch+switch and similar approaches is that they are
_ugly_. Your try/catch suggestion is no more powerful than
catch+switch, but it is more readable. When you scan the code you see
"try ... catch", and the intention of the code is clear. When you see
"catch ... switch" the intention is not clear -- you have no idea that
these two statements are related, and if they are then on what basis are
you switching, etc.
If one accepts that Tcl return codes should be used for flow control,
and that the Tcl return code 1 (TCL_ERROR) covers all errors (which are
called structured exceptions in languages like C++ and Java), and that
there is a need to distinguish between different structured exceptions
(Tcl errors) based on their cause/type/class/nature (whatever you want
to call it), then the inescapable conclusion is that there needs to be a
not-ugly control structure to handle branching based on return code, and
a not-ugly control structure to handle branching based on error cause.
They may or may not be the same control structure, but they are both
equally necessary.
> Perhaps I am wrong here, and glob-matching meets all requirements.
Maybe, maybe not. I'm honestly not sure either way. Assuming that
errorCode is constructed in a hierarchical manner (most general class
first, becoming progressively more specific) then I can't think of a
situation that a glob match can't handle (where an equivalent situation
exists in say Java or C++ that can be handled by their syntax).
Of course its entirely possible that some bright spark declares that if
the general class of errorCode is "OBJECT" then [lindex $errorCode 1] is
an oo::object that is a child of tcl::errorobj, and you want to do
class-based matching on said object. This is probably quite a strong
argument against glob matching (as the only option).
> Personally, if errorcode matching was to take off, I would use some
> form of algebraic types (tagged lists) both for constructing and
> pattern-matching errorcodes, as that seems to me to be the most
> appropriate tool for the job. Perhaps there is a way to keep the
> behaviour but to parameterise the matching command (with switch
> -glob/string match being the default).
Yes, there is, maybe. More below.
> The other question is whether these cases arise in practice. I can't
> think of a single existing API that requires this kind of errorcode
> pattern matching. Is such a design even appropriate? Clearly, if you
> controlled the authentication scheme interface then you could just
> return continue for BADAUTH and an error for anything else:
Depending on your understanding of "pattern matching" ... Java. Like
the whole Java Runtime Library.
Java obviously doesn't use globs to match exceptions, but it does throw
different exceptions and you can catch a group of exceptions based on a
pattern (specifically: the exception object is of a particular class).
errorCode is defined as being a list where the first element identifies
the general class of errors; assuming that this format is maintained
(for legacy compatibility) the most obvious approach to asking "is this
an IO error" is "IO *".
So I have been suggesting "string match" on a structured list as an
approximation of the 'isa' / 'typeof' operator.
My point here applies most specifically to cases where you don't control
the API (which is rather common), but also to cases where you don't want
to modify the API - because it will affect other working code that you
don't want to refactor, or because you believe that adding a flow
control statement like 'break' or 'continue' outside of a flow control
construct is an inherently dangerous code practice because developers
using APIs don't expect stuff like that.
> 4. Trapping only those errors/exceptions you are interested in
> It's clear from the above that the Twylite/JE approach achieves this
> for errors, but not for other exceptions. My approach achieves it for
> exceptions but not for more specific error cases.
I disagree -- is this statement based on a misunderstanding of what
'except' / 'handle' was doing?
> I'd really prefer things to be unified in name at least: "on error",
> "on break", etc. One possible unification that might please all would
> be to adopt the syntax "on exception-type ?pattern? ?vars? body". The
> pattern is an optional glob-style pattern that is matched against the
> -errorcode of the exception. (If the pattern is specified then so must
> the vars). Clearly this is mostly useful in the case of errors, but I
> believe it is possible for non-error exceptions to also set
> -errorcode, so it might be useful elsewhere. That would result in the
> following use-cases:
Anything can set return options (including -errorcode) by using
[return], but only a code 1 return ( [error] ) automatically adds the
-errorcode to the dict.
> proc connect {schemes host user pass} {
> foreach scheme $schemes {
> try {
> return [$scheme connect $host $user $pass]
> } on error BADAUTH {} { continue }
> }
> error "unable to authenticate"
> }
> To me this seems like a good compromise, and people who want more
> complex pattern matching can still do so. I'd like to be able to
> support lists of exception types. I still don't believe glob-style
> errorCode pattern matching is useful or particularly satisfactory, but
> I'm willing to concede it for the sake of compromise. As before,
> define "then" as "on ok", and possibly define "else/otherwise" as a
> catch-all default clause.
It looks promising, but I doubt that errorCode is every really
meaningful outside the context of TCL_ERROR, and I'm leaning towards
glob being insufficient as the only supported matching style. It's all
your fault for being right ;p
> <aside>
> I also see this meshing nicely with a hypothetical future
> continuation-based exception mechanism that allows
> resumable/non-destructive exception/warning notifications.
> </aside>
I've been glimpsing some opportunities here, but I don't work with CPS
enough to have a good idea of how to work it in.
>> On supporting widely-used idioms, it would be much more important IMO
>> to branch based on the result than on the return code. Branching
>> based on return code (i.e. exception handling) is useful for creating
>> new control structures, but if you want to handle errors then you
>> must branch based on some information that is available from a return
>> code = TCL_ERROR (2). That means either errorCode or result, and
>> right now most APIs are using result.
>> You make a good point about leaving pattern matching to existing
>> commands -- I have been thinking along those lines for how best to
>> exploit that (more in another mail).
> Branching based on the result just seems like a fragile nightmare.
> Localised error messages for instance could totally change the
> behaviour of code.
Oh, it is ;( But its also the only option available in some existing
libraries. I've encountered code that puts an error identified in the
result and the error message in errorInfo, for example.
The question then is: how widespread is such (bad) code. Would
developers regularly resort to another branching mechanism (try+switch,
catch+switch, etc.) or would they be able to use the new [try] for the
vast majority of their code?
>> Let's drop to Java-speak for a moment: the current practice of Tcl
>> developers is to "catch (Exception e) { // handle }". In C++ it is
>> "catch (...) { // handle }".
>> Return code is not a mechanism for exception/error typing, it is a
>> mechanism for implementing control flows. We need a typing mechanism.
> Hmmm... error handling needs case-analysis not typing per se. Clearly,
> any mechanism used for constructing error cases is strongly related to
> the mechanism that is used for distinguishing them, which is why I'd
> rather see these aspects separated/parameterised from the exception
> handling, at least until it is clear what the best mechanism for this is.
I'm going to take a stab at identifying what the best mechanism is.
Let's move back for a moment to what we're trying to achieve here.
Functionality:
a. Handle errors by class (errorCode)
b. Handle success continuation (i.e. don't limit the control structure
to only exceptional situations)
c. Handle other (non-error) exceptions
d. It is clear that (a), (b) and (c) are all specialisations of
matching the Tcl return code (and possibly some other return
information, like errorCode and result)
e. Clean up at the end of an operation, regardless of errors/exceptions
Look & Feel:
a. Looks like if/then/else (traditional structured try/catch as in
C++, Java, etc), OR
b. Looks like switch (I don't actually know of another language that
does this), OR
c. Hybrid of (a) and (b): choose between success/error with an
if/then/else like construct, then switch on the specific result/error
(e.g. Erlang)
Matching:
a. Match a single return code, a range of return codes, or a discrete
list of return codes
b. Match a specific error code, and an errorcode pattern (glob-like)
c. Possibly provide for more complex matches involving other fields
(result), regular expressions, disjunctive matching, case sensitivity,
relational calculus/algebra, whatever.
catch+something_else can provide for arbitrary complexity. Should [try]
also do so, or should its complexity be limited? If limited, what is a
reasonable limit? Exact match? Range match? Glob match?
It strikes me that there are two possible solutions:
(1) Make [try] an unholy union of [catch] and [switch] such that the
user can specify the information being switched on (e.g. "%C,%E,%R"
where %C is the return code, %E is the errorcode and %R is the result).
You delegate pattern matching to [switch] and allow the user to match
based on any combination of return code, errorcode and result.
try {
# ...
} thenwith -glob -- "%C,%E" {
"1,POSIX *" { handle posix errors }
"3,*" -
"4,*" { handle break/continue }
}
(2) Make [try] an unholy union of [catch] and [if]/then/else, and
provide helper functions/operations to match exception/error cases with
expr.
try {
# ...
} handle { [string match "POSIX *" $::errorCode] } {
handle posix errors
} handle { code() in {3 4} } {
handle continue
}
Asssuming some minor changes to expr that could look more like:
try {
# ...
} handle { errorcode() like "POSIX *" } {
} handle { code() in {3 4} } {
}
I found the question on Reddit at
http://www.reddit.com/r/programming/comments/7dgwy/ask_proggit_where_clauses_in_catch_declarations/?sort=old
quite interesting in this regard.
Ick ... time to get home.
Twylite
|
|
From: Donal K. F. <don...@ma...> - 2008-11-20 16:29:09
|
Techentin, Robert wrote: > As far as an implementation goes, I don't know how to handle systems > that don't supply mkstemp(). (That was the main reason I stopped pusing > four years ago.) My MSDN V6 documentation tells me that MS Windows > doesn't have that function. I'm sure there are other systems supported > by Tcl that don't have mkstemp() available. How do you handle that? Right now, we only support POSIX and Win. (In this respect, OSX is POSIX, which is good.) With POSIX, we cam use mkstemp() or mkstemps(). Windows is rather lacking in this area, and one has to fall back on a combination of GetTempFileName, GetTempPath, and CreateFile. Donal. |
|
From: Techentin, R. <tec...@ma...> - 2008-11-20 15:32:02
|
Donal wrote: > > I've revised the TIP to swap those arguments as suggested. (While the > TIP previously allowed template to be blank, that was still messy and > non-obvious!) I've also made it much clearer what the template format > actually is, and I hope that someone can check that I've not messed it > up in the process. Assuming I've not blundered, it's now good to go. I'm delighted to see some interest in TIP #210. (My apologies for being late to the party.) I see some changes to the TIP, and I think the suggestions are great. But I can't tell exactly what else is getting done, and I'd like to help, if possible. The patch I submitted a while back was, well, a little lame. It only exposed tempname() functionality. The proposed solution would be much more sophisticated, including default templates for different platforms and significantly more error handling. Has anybody worked on that? Or has the activity just been to specify behavior in the TIP? As far as an implementation goes, I don't know how to handle systems that don't supply mkstemp(). (That was the main reason I stopped pusing four years ago.) My MSDN V6 documentation tells me that MS Windows doesn't have that function. I'm sure there are other systems supported by Tcl that don't have mkstemp() available. How do you handle that? Thanks, Bob -- Bob Techentin tec...@ma... Mayo Foundation (507) 538-5495 200 First St. SW FAX (507) 284-9171 Rochester MN, 55901 USA http://www.mayo.edu/sppdg/ |
|
From: Neil M. <ne...@Cs...> - 2008-11-20 13:40:54
|
Twylite wrote:
> And there I was thinking this had been discussed on tcl-core ;)
>
> First up, I want to be clear about the intent behind TIP #329:
> a) The TIP is about error handling, not exception handling. Tcl has
> excellent exception handling which can be readily used in a mostly
> non-ugly way (e.g. catch + if/then/else or catch + switch), but its
> error handling is poor.
I don't agree that exception handling is excellent in Tcl currently.
> Developers use the result (Tcl_SetResult, not
> return code) as an error message, representing both the class/category
> and exact nature of the error (in a human-readable form), but don't
> provide a way to programatically identify the class of error making
> control flow based on the type of error a hit-and-miss match on the
> error code.
I believe this is already addressed by the presence of errorCode.
Pattern-matching against this code is already quite simple, with
[switch] and so on. It just hasn't caught on. It seems like wishful
thinking to expect that it will suddenly catch on just because its usage
is made slightly more convenient (we're talking about a reduction of
about 1 line of code).
> b) The innovation of a new 'finally' that simplifies the linguistic
> expression of the programmer's desires has been a large part of my
> motivation to develop this TIP.
I agree with the motivation for this entirely.
> c) The overall intent of the TIP can be summed up as "make a control
> structure that makes dealing with errors and resource cleanup simpler -
> both logically and visually".
I think it is worth explicitly pulling out the separate concerns
embodied in this TIP and tying them to use-cases. As I see it, there are
a number of more-or-less separable concerns here:
1. Support for ensuring resource cleanup in the presence of
exceptions/errors (i.e. "finally").
2. Better support for case-analysis based on exception return code.
3. Better support for case-analysis based on errorcode.
4. Ability to trap only those exceptions/errors that you are interested
in/prepared to deal with, letting others propagate normally.
Now, it we look at some use-cases and how they are handled currently,
versus proposed methods for handling them:
1. Guaranteed resource cleanup
------------------------------
A typical example of this is ensuring that a channel is closed once we
have finished processing it. Currently, you would do this via:
set chan [open $myfile r]; # or [socket] etc
catch { process $chan } msg opts
close $chan
return -options $opts $msg
Some things to notice here are: (a) the catch-all behaviour of [catch]
is exactly what is required here: we don't want any exceptions to
escape, (b) we don't require any case-analysis on the exception type or
error code. The proposed alternative is:
set chan [open $myfile r]
try { process $chan } finally { close $chan }
This is a saving of two lines, but I think the improvement in
readability is worth it. A possible improvement would be for any errors
in the finally clause to not completely mask any errors in the main
script -- perhaps by adding a -original field to the options dict (which
itself contains the message and options dict of the original error).
I'd be happy to see this part of the TIP dropped or separated into a
different command however.
2. Case-analysis based on return code
-------------------------------------
An example here is that of implementing custom control structures. Of
particular interest here is the use of standard exceptions like [break]
and [continue]. For instance, we may want to write a version of
[foreach] that operates asynchronously using the event loop. Currently,
we might write this as:
proc async-foreach {varName list body} {
if {[llength $list] == 0} { return }
set list [lassign $list item]
set code [catch { apply [list $varName $body] $item } msg opts]
switch $code {
3 { return }
0 - 4 { # ok/continue }
default { return -options $opts $msg }
}
after 0 [list async-foreach $varName $list $body]
}
(I can never remember whether you need to [dict incr opts -level] in
these situations).
The try/handle (Twylite/JE) alternative would be:
proc async-foreach {varName list body} {
if {[llength $list] == 0} { return }
set list [lassign $list item]
try {
apply [list $varName $body] $item
} handle {code msg opts} {
switch $code {
3 { return }
0 - 4 { # ok/continue }
default { return -options $opts $msg }
}
}
after 0 [list async-foreach $varName $list $body]
}
This is slightly longer and introduces more nesting than the original.
In general, it seems to hamper rather than improve readability. By the
way, does "handl" catch all exception types, or just non-errors? In
general, try/handle seems just a more verbose version of the existing
[catch].
The alternative using try/catch would be:
proc async-foreach {varName list body} {
if {[llength $list] == 0} { return }
set list [lassign $list item]
try {
apply [list $varName $body] $item
} catch break {} { return } catch continue {} {}
after 0 [list async-foreach $varName $list $body]
}
This scheme is shorter. It is more readable as we have symbolic names
"break" and "continue" rather than magic numbers, and it avoids catching
anything it doesn't know how to deal with.
Note that dispatch based on exception code is a simple branch. There is
no need for complex pattern matching, sub-match capture, or
case-insensitive matching.
3. Case-analysis based on errorcode
-----------------------------------
For this, I'll use Twylite's example of trying different authentication
schemes. We will assume that the API throws an error with code BADAUTH
when the wrong scheme is used, and throws other errors such as NOCONN to
indicate that a connection to the host failed. (Note: this example
doesn't require glob-matching, but I don't think the changes in such a
case are that great). The existing way to handle this would be:
proc connect {schemes host user pass} {
foreach scheme $schemes {
if {[catch { $scheme connect $host $user $pass } res opts]} {
switch [dict get $opts -errorcode] {
BADAUTH { continue }
default { return -options $opts $res }
}
} else { return $res }
}
error "unable to authenticate"
}
Using the proposed try/onerror approach, this would be:
proc connect {schemes host user pass} {
foreach scheme $schemes {
try {
return [$scheme connect $host $user $pass]
} onerror BADAUTH { continue }
}
error "unable to authenticate"
}
Using try/catch:
proc connect {schemes host user pass} {
foreach scheme $schemes {
try {
return [$scheme connect $host $user $pass]
} catch error {msg opts} {
switch [dict get $opts -errorcode] {
BADAUTH { continue }
default { return -options $opts $msg }
}
}
}
error "unable to authenticate"
}
OK, in this case the try/onerror approach certainly is clearer, and the
try/catch approach is little better than the existing way with [catch]
alone. I think it still wins slightly over [catch] in readability. While
it is more verbose, the control flow is easier to read -- the [return]
is in an obvious place, and not tucked away in an inconspicuous "else"
clause. There's also less punctuation. But the onerror approach is
clearly better for this case.
The questions then, are whether "onerror" is sufficient for all/most
such cases, and whether these cases actually arise often/ever in
practice (or would arise given appropriate promotion). Regarding the
first part, dispatching based on errorcode is more complex than based on
return code as while the latter is a simple integer, the former can be
an arbitrarily complex data structure. In particular, the following
requirements may have to be considered:
a. Different forms of pattern-matching (e.g. exact, glob, regexp,
"algebraic" type matching etc). If we stick to one type only, will that
be appropriate? Will it cause problems? (e.g. if glob-only matching,
then we have problems specifying glob-special characters such as * or []).
b. Case sensitivity -- is "arith" the same error as "ARITH" or "ARiTh"?
c. Sub-match capture: an errorcode may contain detail fields which we
want to extract. It seems pointless to match once and then perform a
separate extraction when I could have just used [regexp] or some other
matching facility and performed both operations in one go.
d. Disjunctive matching: perform this action if the errorcode matches
either *this* or *that*.
I'm sure there are others. To me, the range of choices here suggests
that pattern matching is best kept separate from error-handling.
Otherwise there is a risk of duplicating [switch]. Perhaps I am wrong
here, and glob-matching meets all requirements. Personally, if errorcode
matching was to take off, I would use some form of algebraic types
(tagged lists) both for constructing and pattern-matching errorcodes, as
that seems to me to be the most appropriate tool for the job. Perhaps
there is a way to keep the behaviour but to parameterise the matching
command (with switch -glob/string match being the default).
The other question is whether these cases arise in practice. I can't
think of a single existing API that requires this kind of errorcode
pattern matching. Is such a design even appropriate? Clearly, if you
controlled the authentication scheme interface then you could just
return continue for BADAUTH and an error for anything else:
proc connect {schemes host user pass} {
foreach scheme $schemes {
return [$scheme connect $host $user $pass]
}
error "unable to authenticate"
}
4. Trapping only those errors/exceptions you are interested in
--------------------------------------------------------------
It's clear from the above that the Twylite/JE approach achieves this for
errors, but not for other exceptions. My approach achieves it for
exceptions but not for more specific error cases.
> NEM:
>> Firstly, "onerror" and "except" seem like bad names to me. "except" in
>> particular would imply that the following error case *isn't* handled (as
>> in "catch everything *except* for these..."), which is just confusing.
>> I also have some problems with the usage. I'd prefer to see something
>> like:
> I accept your argument about "except", having had the same concern
> myself. I drew this from C's try...except. Others have argued against
> the use of 'catch' as it could be confused with the existing catch
> command. I'll consider 'handle' instead of catch - it sounds reasonable
> for the domain; other suggestions are welcome. I feel that "onerror" is
> correctly named though.
I'd really prefer things to be unified in name at least: "on error", "on
break", etc. One possible unification that might please all would be to
adopt the syntax "on exception-type ?pattern? ?vars? body". The pattern
is an optional glob-style pattern that is matched against the -errorcode
of the exception. (If the pattern is specified then so must the vars).
Clearly this is mostly useful in the case of errors, but I believe it is
possible for non-error exceptions to also set -errorcode, so it might be
useful elsewhere. That would result in the following use-cases:
proc connect {schemes host user pass} {
foreach scheme $schemes {
try {
return [$scheme connect $host $user $pass]
} on error BADAUTH {} { continue }
}
error "unable to authenticate"
}
proc async-foreach {varName list body} {
if {[llength $list] == 0} { return }
set list [lassign $list item]
try {
apply [list $varName $body] $item
} on break { return } on continue {}
after 0 [list async-foreach $varName $list $body]
}
To me this seems like a good compromise, and people who want more
complex pattern matching can still do so. I'd like to be able to support
lists of exception types. I still don't believe glob-style errorCode
pattern matching is useful or particularly satisfactory, but I'm willing
to concede it for the sake of compromise. As before, define "then" as
"on ok", and possibly define "else/otherwise" as a catch-all default clause.
<aside>
I also see this meshing nicely with a hypothetical future
continuation-based exception mechanism that allows
resumable/non-destructive exception/warning notifications.
</aside>
[...]
> On supporting widely-used idioms, it would be much more important IMO to
> branch based on the result than on the return code. Branching based on
> return code (i.e. exception handling) is useful for creating new control
> structures, but if you want to handle errors then you must branch based
> on some information that is available from a return code = TCL_ERROR
> (2). That means either errorCode or result, and right now most APIs are
> using result.
> You make a good point about leaving pattern matching to existing
> commands -- I have been thinking along those lines for how best to
> exploit that (more in another mail).
Branching based on the result just seems like a fragile nightmare.
Localised error messages for instance could totally change the behaviour
of code.
[...]
>> People don't do it because it just isn't very useful. Errors in Tcl
>> tend to be real errors -- other than logging them, there is often not
>> much to do. Tcl's introspection, use of general control exceptions
>> like [continue]/[break], and custom control structures/HOFs etc make
>> this kind of exception-based case analysis much less necessary. I may
>> well be wrong about this, but I'd prefer to see some concrete use-cases.
> The nature of errors in Tcl is a side-effect of the weak support for
> distinguishing between types of errors. This functionality is useful
> any time that you are calling into an opaque API and can take different
> recovery actions based on the cause of the error. e.g. you want to wrap
> load balancing and/or fault tolerance (simplest case: auto-reconnect)
> around an RPC or DB interface; you want to try alternative
> authentication schemes when the password fails (but not when the
> connection fails, or the protocol is mismatched); you want to tell the
> user whether to 'try again later' or 'call the administrator'.
Thanks for these use-cases.
> Let's drop to Java-speak for a moment: the current practice of Tcl
> developers is to "catch (Exception e) { // handle }". In C++ it is
> "catch (...) { // handle }".
> Return code is not a mechanism for exception/error typing, it is a
> mechanism for implementing control flows. We need a typing mechanism.
Hmmm... error handling needs case-analysis not typing per se. Clearly,
any mechanism used for constructing error cases is strongly related to
the mechanism that is used for distinguishing them, which is why I'd
rather see these aspects separated/parameterised from the exception
handling, at least until it is clear what the best mechanism for this is.
[...]
-- Neil
This message has been checked for viruses but the contents of an attachment
may still contain software viruses, which could damage your computer system:
you are advised to perform your own checks. Email communications with the
University of Nottingham may be monitored as permitted by UK legislation.
|
|
From: Donal K. F. <don...@ma...> - 2008-11-20 10:52:33
|
Joe English wrote: >> TIP #210 Add 'tempname' Subcommand to 'file' > > Same as before: change the order of the arguments from > > file tempfile ?template? ?namevar? > to > file tempfile ?namevar? ?template? > > and it's good to go. As currently specified, it forces callers > to supply a template if they want to get the filename back. > One of the main points of the TIP is for Tcl to take care > of all the hairy platform-specific details of where temp files > should go; the propsed interface defeats that. I've revised the TIP to swap those arguments as suggested. (While the TIP previously allowed template to be blank, that was still messy and non-obvious!) I've also made it much clearer what the template format actually is, and I hope that someone can check that I've not messed it up in the process. Assuming I've not blundered, it's now good to go. Donal. |
|
From: Twylite <tw...@cr...> - 2008-11-20 10:51:47
|
And there I was thinking this had been discussed on tcl-core ;)
First up, I want to be clear about the intent behind TIP #329:
a) The TIP is about error handling, not exception handling. Tcl has
excellent exception handling which can be readily used in a mostly
non-ugly way (e.g. catch + if/then/else or catch + switch), but its
error handling is poor. Developers use the result (Tcl_SetResult, not
return code) as an error message, representing both the class/category
and exact nature of the error (in a human-readable form), but don't
provide a way to programatically identify the class of error making
control flow based on the type of error a hit-and-miss match on the
error code.
b) The innovation of a new 'finally' that simplifies the linguistic
expression of the programmer's desires has been a large part of my
motivation to develop this TIP.
c) The overall intent of the TIP can be summed up as "make a control
structure that makes dealing with errors and resource cleanup simpler -
both logically and visually".
NEM:
> Firstly, "onerror" and "except" seem like bad names to me. "except" in
> particular would imply that the following error case *isn't* handled (as
> in "catch everything *except* for these..."), which is just confusing.
> I also have some problems with the usage. I'd prefer to see something
> like:
I accept your argument about "except", having had the same concern
myself. I drew this from C's try...except. Others have argued against
the use of 'catch' as it could be confused with the existing catch
command. I'll consider 'handle' instead of catch - it sounds reasonable
for the domain; other suggestions are welcome. I feel that "onerror" is
correctly named though.
> Certainly, I think dispatch based on the return code/exception type
> should be at least as easy as based on errorCode -- I can think of lots
> of examples of Tcl code that does this, but almost none that actually
> looks at errorCode.
While my aim in this TIP was to deal with errors, there has been a
strong call to generalise the control structure to handle exceptions.
My feeling is that it should handle both with equal ease.
> Support for existing, widely-used idioms, should be as much, if
> not more, important than promoting lesser-used alternatives. In fact,
> I'd leave out entirely the glob-matching on errorCode, and let people do
> this with [switch] if they want it:
I cannot agree with this -- it would make this try/catch a control
structure focused exclusively on exceptions (not on errors), and provide
no functional or syntactic benefit over catch+switch (other than a
'finally' clause).
On supporting widely-used idioms, it would be much more important IMO to
branch based on the result than on the return code. Branching based on
return code (i.e. exception handling) is useful for creating new control
structures, but if you want to handle errors then you must branch based
on some information that is available from a return code = TCL_ERROR
(2). That means either errorCode or result, and right now most APIs are
using result.
You make a good point about leaving pattern matching to existing
commands -- I have been thinking along those lines for how best to
exploit that (more in another mail).
> Show me the use-cases! Handling different error-cases with [catch] is
> not that ugly now:
The exact same example switched on the return value of catch, or on
[dict get $opts -code], handles exceptions with the same level (or lack
thereof) of ugliness. Arguably if one does not need a different control
structure for errors, then it is no more necessary for exceptions.
> People don't do it because it just isn't very useful. Errors in Tcl
> tend to be real errors -- other than logging them, there is often not
> much to do. Tcl's introspection, use of general control exceptions
> like [continue]/[break], and custom control structures/HOFs etc make
> this kind of exception-based case analysis much less necessary. I may
> well be wrong about this, but I'd prefer to see some concrete use-cases.
The nature of errors in Tcl is a side-effect of the weak support for
distinguishing between types of errors. This functionality is useful
any time that you are calling into an opaque API and can take different
recovery actions based on the cause of the error. e.g. you want to wrap
load balancing and/or fault tolerance (simplest case: auto-reconnect)
around an RPC or DB interface; you want to try alternative
authentication schemes when the password fails (but not when the
connection fails, or the protocol is mismatched); you want to tell the
user whether to 'try again later' or 'call the administrator'.
Let's drop to Java-speak for a moment: the current practice of Tcl
developers is to "catch (Exception e) { // handle }". In C++ it is
"catch (...) { // handle }".
Return code is not a mechanism for exception/error typing, it is a
mechanism for implementing control flows. We need a typing mechanism.
JE:
> I would suggest:
>
> try {
> ...
> } onerror {pattern ?resultVar ?optionsVar??} {
> #
> # return code was TCL_ERROR, errorCode matches $pattern
> #
> } handle {code ?resultVar ?optionsVar??} {
> #
> # return code was $code.
> #
> } finally {
> ...
> }
>
Based on NEM's argument against 'except', this is pretty much what I'm
left with (with 'then' as an alias for 'handle ok').
>> > I still have concerns about this though:
>> > - The construct is getting pretty bulky - is it really adding power &
>> > simplicity as it is intended to do?
>>
> Yes. Dispatching based on the return code is essential
> for creating user-defined control structures.
>
There seems to be a consensus that the try/catch structure needs to
handle return codes (at least as easily at errors).
>> > The only real question is whether
>> > the msgvar and optvar should be that way round. Pass on that! :-)
>>
> Yes, they are in the right order.
>
Agreed - the order {emvar optsvar} is consistent with catch.
> I believe so. Nested try/finally clauses -- one for each
> resource that needs to be cleaned up -- all wrapped in
> an outer try/catch for error recovery would cover
> all the exception handling needs I can think of.
>
> I don't like the alternative approach much either,
> simply because it smells too much like innovation.
>
And there I was thinking that Tcl generally supported innovation ;p
That troll-hole aside, I do a lot of work in C, especially firmware for
embedded systems. Not having syntax for exception handling, there are
two approaches you can take to code flow and resource cleanup:
1) Deeply nested logic. Your "ideal path" reads diagonally as you
acquire resources and check conditions in nested if/then/else
statements. There is one point of return at the end of the function.
2) Fail-fast logic. Your code reads down the page; when an error is
encountered to jump (goto) a cleanup block at the end of the function.
Your code never indents for error codes, only for non-error branches.
Although the only return is at the end of the function this is a
consequence of the lack of try/finally syntax - in effect each 'goto' is
a point of return.
If you've never encountered non-trivial functions written in these two
styles, I suggest you take a look. The latter is (by my reckoning and
that of all experienced developers I've worked with) far more readable,
understandable and maintainable. YMMV, as may your opinion.
The whole point of exception handling (by which I mean
Java/C++/Python/Ruby/whatever, not Tcl's
use-a-return-code-for-flow-control) is to support the fail-fast paradigm
in conjunction with not having to explicitly check for failure on each
call (exceptions branch the flow at the point of the call and propagate
up the stack). If your code must still be deeply nested in order to
(safely) handle cleanup then are you really gaining anything from
exception handling? Your code remains visually complex, and the benefit
of the new syntax is limited.
Looking at this another way, you _could_ use nested try/finally clauses
in Java, C++, etc. to avoid the common bugs in finally clauses (freeing
an unallocated resource, not handling exceptions off resource
deallocation leading to dangling resources) but _developers don't_. It
could be laziness, incompetence, lack of care, lack of testing, not
having been caught by the bugs enough, not being aware of the problem,
or simply that its too much of a pain to do it properly. I don't know
for sure, but from my interactions with developers in my company I'm
leaning towards the last reason.
> There has been a longstanding desire that people [*] make
> better use of -errorcode, but there's a vicious cycle:
> nobody bothers to use meaningful -errorcodes because nobody
> bothers to check -errorcode because there's no convenient
> way to do so.
>
> try/onerror would at least break that part of the cycle.
>
This is the intention of the TIP, yes.
Regards,
Twylite
|
|
From: Andreas L. <av...@lo...> - 2008-11-20 08:52:39
|
"Jan Nijtmans" <nij...@us...> wrote: > The patch for TIP #340 is available now, and the description of the > TIP is updated: > http://sourceforge.net/tracker/index.php?func=detail&aid=2315890&group_id=10894&atid=310894 I think a mention of Tcl_SetObjResult (or other alternatives) should be added to the Deprecation-block. One could argue that the referral to the TIP covers it, but I still think it would be a good thing to have that piece of information immediately at hand without having to look up the TIP. |
|
From: Andreas K. <aku...@sh...> - 2008-11-20 02:20:20
|
> >> For non-interactive use the same would fail, but the error message > >> could be extended with a hint about availiable near-matches: > >> > >> can't find package tk (perhaps you meant Tk) > That's not the way the [package require] implementation makes use of > the [package unknown] handler. > As written, [package require tk $requirement] will pass along > arguments "tk" and $requirement (if any) to the [package unknown] > handler. The contract is that the [package unknown] handler should > find packages that match what it was told to look for. If it wants, > it can look for other things too and the default one does, but that > has not been required. Yes. And a big thank you for reminding me of this, as I am currently not adressing this in the TIP at all, and will have to. > So, either we would need to change the contract so that [package > unknown] handlers are expected to search for matching packages of > all cases variations, causing some existing [package unknown] > handlers to become "broken" according to the new standard, I believe I am prefering this over the proposal below. > or [package require] would need to iterate over all the case > variations and call the [package unknown] handler again and again > until at least something satisfying the requirement appeared, or > possibly until all cases were covered. Eh ... n characters, two cases => 2^n possibilities. No. Not liking this at all. Changing the contract ... The standard unknown handler needs no changes, as it inserts everything it finds into the database. The TM handler on the other hand will need modifications, as glob is case-sensitive. Well, maybe not on Windows. -- So long, Andreas Kupries <aku...@sh...> <http://www.purl.org/NET/akupries/> Developer @ <http://www.activestate.com/> ------------------------------------------------------------------------------- |