|
From: Neil M. <ne...@Cs...> - 2008-11-22 14:08:36
|
On 22 Nov 2008, at 03:49, Magentus wrote:
> On Thu, 20 Nov 2008 10:39:26 -0800,
> Joe English <jen...@fl...> wrote:
>
>> handle {code ?resultVar ?optionsVar??} { script }
>
> Is there any actual practical use to putting code in the braces? The
> variables, I don't think can be avoided in this style, although I'm
> not
> sure that there is a need to have every single branch specify the
> variables individually. I'd much prefer to have them specified
> once at
> the top (and optionally at that) rather than repeated monotonously on
> every single branch.....
Agreed on both counts.
> [...]
> Supporting all the different types of match, though, would be a "Good
> Thing". -glob, -nocase, -exact, -prefix, -regexp, and so forth...
> That's why I think the next part is worth giving a second thought.
If these are supported it should be only by explicit delegation to
[switch], rather than making all these options part of the interface
of [try] too.
I proposed the following interface offline to Twylite (slightly
altered) yesterday:
try ?-matchcommand cmd? script ?handlers ...? ?finally script?
Where -matchcommand is the command to use to do errorCode matching
and defaults to {switch -glob --}. (May need a -- marker to eliminate
ambiguity). The syntax of the handlers part would be:
on exception-types ?vars? ?errorPattern? body ?errorPattern
body ...?
Where exception-types is a list of one or more of "ok", "error",
"return", "break", "continue" or an integer return code. errorPattern
is a pattern (specific to the -matchcommand) used to match against
the -errorcode (if any). ?vars? is a list of var names {?resultVar ?
optsVar??} and finally "body" is a script. If you want to specify the
errorPattern you must also specify the vars, to avoid ambiguity. If
you want to specify multiple patterns, then the first errorPattern is
mandatory. The try command then builds a lookup table mapping return
code -> (ordered) dict of patterns/scripts. It does a simple lookup
based on the return code of the initial script and then passes the
errorCode and dict of patterns to the -matchcommand, i.e. it would
become [switch -glob -- $errorCode $handlers]. If there is no
errorCode (e.g. a non-error exception) then the empty string is
passed. A "default" branch is also added to the end of the handlers
which just rethrows the exception, or if a branch with no pattern is
specified then this becomes the default branch. The body of a handler
can be "-", with the same meaning as in [switch]. To be concrete, the
syntax would look something like:
try {
...
} on error {msg opts} {IO *} - {POSIX *} {
...
} {ARITH *} {
...
} on {break continue} {
...
} finally {
...
}
You could also write those "on error" clauses as:
} on error {msg opts} {IO *} - {POSIX *} {
...
} on error {msg opts} {ARITH *} {
...
}
Or any combination of the styles you prefer (the former allows you to
specify the vars once, the latter may be more readable). The core
dispatch then becomes something like:
set rc [catch { $script } msg opts]
invoke 1 {*}$matchcmd [dict get $opts -errorcode] [dict get
$handlers $rc]
As before, "then" could be taken as sugar for "on ok", and some catch-
all "else/otherwise" could be added.
It seems to me that this covers most (all?) use-cases, while still
keeping [try] relatively minimal and efficient. In particular, [try]
avoids acquiring the interface of any particular pattern matching
construct. It can also support various types of matching (e.g. I can
use algebraic types, OO enthusiasts can use sub-class matching, and
others can use arbitrary expressions). The core [try] command only
needs to implement basic return-code based matching, which is O(1),
so remains efficient for those implementing control structures over
the top of this. Examples of customisation:
interp alias {} datatry {} try -matchcommand {datatype match}
interp alias {} regtry {} try -matchcommand {switch -regexp -
nocase --}
interp alias {} exptry {} try -matchcommand expmatch
proc expmatch {code cases} {
foreach {case body} $cases {
if {$case eq "default" || [expr $case]} { return [uplevel
1 $body] }
}
}
exptry { ... } on error {msg opts} {[lindex $code 2] > 1000} { ... }
Thoughts? I'm sure the syntax may need some jiggling to get order of
things optimal and to eliminate any remaining ambiguities.
-- 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.
|