|
From: Twylite <tw...@cr...> - 2008-11-23 11:13:16
|
Hi,
>>> 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.....
>>>
>> This fits with extending [catch], e.g.
>> catch { ... } em opts then { ... } handler {...}
>> The feedback I've had so far on this approach has not been
>> favorable. It seems that developers would prefer to keep the
>> args/vars in the context of the handler body.
>>
> Hmmm..... Fair enough. My reasoning is this:
>
> - Restricts and confuses the arguments to the individual handlers.
> They're obvious, mostly redundant, and get in the way of other more
> useful potentially optional arguments.
>
> - What happens if each handler specifies a different set of variables.
> Which ones will be defined when the code block completes? Or are they
> only defined within the context of the handler being invoked? It's
> confusing.
>
> Having them specified up front makes it obvious that they're set within
> the current scope, and hence will be available both to the invoked
> handler and to code following the [try] block.
>
Looking at the recent "pluggable matcher/handler" proposals it is
becoming clear that the vars must be defined before the "errorPattern"
is evaluated - in the case of an [expr] type handler the errorPattern
may be an expression that involves the return code, result and options,
so they must be brought into scope before the pattern is checked.
Your second point (what is defined when a block completes) is also a
good one - I was wondering about this last night. Having the vars from
all handlers defined would be unexpected (and in most cases a lot of
extra work); having vars from only the executed handler would mean a lot
of pulling vars into & out of scope until the right handler is found,
and then potential for errors in the code following the [try] as it
dereferences the wrong variable name.
Taken together these are a strong argument in favour of defining the
vars up front.
An unfortunate consequence of this is that handlers become harder to reuse.
>>> 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.
>>>
A little more on this one: accessing the return options in the [expr]
would be painful, because it requires using [dict]. It would be fairly
trivial to implement mathfuncs for code(), errorcode() and opts(-what)
that would do the right thing.
>> Not that I'm aware of, no. My current thinking is that it will be
>> outside the brackets, e.g.
>> handle code/expr {?resultvar? ?optionsvar?} { body }
>>
> That would be _much_ preferable. I do think, though, that being able
> to glob-match on a returned value is a requirement to being worth the
> effort. Otherwise you'll have a bunch of branches each with an
> embedded [switch] and it's going to look worse, be less useful, and
> probably less efficient, than what I've sometimes done:
>
As several people have pointed out on this list, matching against the
return value is something we want to discourage. It would be possible
via an [expr]-type handler, but I don't think it should be supported by
the default (probably glob-type) handler.
> One possible thought; a "return" (pending a better name) handler that
> matches the return value, and leaving that off from the "on" handler.
> So...
>
> HANDLE errorcode-pattern {...}
> RETURN returnvalue-pattern {...}
> ON return-code {...}
>
> might be better, on the basis that most of the return codes don't allow
> you to specify a return value without producing them directly through
> [return]. Further on that, the return-code could optionally be a list
> of two words with the return value pattern being the second, which
> would allow the "on" form to handle it transparently without the
> "return" form at all.
>
I'm in favour of pluggable matchers _per handler_, which would allow you
to do this sort of thing (but possibly not with the default handlers).
e.g.
try {
# stuff
} on error -like "POSIX *" {
} on error -withresult "foo*" {
}
You can define the "withreturn" matcher to do whatever you want (in this
case a glob match against the result)
>> One advantage of having the vars with the handler script is that it
>> allows you to reuse handlers. e.g.
>> set GENERAL_IO_HANDLER {{em opts} { log "Problem: $em" }}
>> ...
>> try {
>> # some IO routine
>> } handle error * {*}$GENERAL_IO_HANDLER
>> And in this case its no coincidence that the GENERAL_IO_HANDLER looks
>> like an anonymous function that can be used with [apply]
>>
> I don't see any advantage to that at all. The handler won't be
> compiled or anything of the kind any more than it would be without the
> vars, and special magic is still going to need to be added to allow it
> to efficiently be re-used with [apply] or [eval] or what-not.
>
Code reuse. If you have a cross-cutting strategy (over several
packages/components in an application or library) for handling a
particular type of error (say IO errors), you can abstract that into a
code snippet that looks like an anon proc. You can only do this if the
proc knows the names of the variables its going to deal with, hence the
advantage of having the vars and body adjacent.
The alternative is to call a proc, but it is slightly less convenient:
try {
# some IO routine
} on error {*}$GENERAL_IO_ERROR_MATCH { do_general_io_error $code $em
$opts }
Besides being slightly more verbose, the pattern constant and the proc
are no longer closely associated in code.
Anyway, I don't think this is a particularly important bit of
functionality -- it would be nice to have, but there are stronger
arguments for having the vars at the front of the [try].
Regards,
Twylite
|