|
From: Neil M. <ne...@Cs...> - 2008-11-23 21:35:18
|
On 23 Nov 2008, at 20:36, Twylite wrote:
> [...]
>>> The stronger argument is the performance impact of bringing per-
>>> handler vars into scope and back out of scope each time.
>>>
>> I don't see this point, could you elaborate? The vars only need to be
>> defined once.
>>
> If the vars are defined per handler, and can be different per handler,
> then multiple different variables must be brought into scope (and
> possibly out again if you don't want them handing around if the
> handler
> didn't match).
> I think the confusion here is what constitutes a "handler" - according
> to all my proposals a "handler" is (return code + optional more
> specific
> pattern), but your recent proposal is (return code + pattern1 +
> pattern2
> + ...). Clearly there would issues of performance and dangling
> variables in the case I am understanding, but not in the case of your
> proposal.
In my scheme only a single handler ever gets as far as defining its
variables. So there is no need to bring multiple sets of vars into
and out of scope.
>> No -- I mean you would have [try] and some [lmatch] command.
>>
> Sorry - misunderstanding.
>
>> I don't see why [try] has to know anything at all about it. It is
>> just passed a callback that takes the errorcode and a list of
>> pattern-
>>> script pairs, and simply calls it, returning whatever it returns
>> (including exceptions). All it needs to do is ensure any "finally"
>> script runs.
>>
> Because [try] is a (core) command that is promising a particular
> interface & behaviour, but the implementation cannot guarantee the
> behaviour as it delegates too much to a matcher that _may_ be
> implemented outside the core.
Then don't guarantee that behaviour.
> And because, as you highlight below, you have to identify and
> compensate
> for the corner cases in the matcher.
>> I don't see this as a problem. If [try] is documented as delegating
>> to a match command then it makes sense for that command to appear in
>> the stack trace. [try] can always pretty up the errorinfo if it
>> helps.
>>
>> A simple equality check would avoid this (a Tcl_Obj pointer
>> comparison). Alternatively, the default script can be manufactured to
>> signal this special condition. It's a problem of implementation not
>> interface.
>>
> All I'm saying is that rather than have the matcher actually
> execute the
> script, it should return it (or the index of the script in whatever
> list/dict was provided to the matcher) and allow the [try] to execute
> the script directly.
Sure, you *could* do that, but that excludes using [switch] or most
other control structures, which expect to directly execute the chosen
branch rather than just returning it. I really don't see what is
gained from having [try] execute the script: it's the difference
between doing [catch {$matchcmd ...}] vs set script [$matchcmd ...];
catch {uplevel 1 $script}.
>>> (1) Performance.
>>>
>>> The largest number of exception handlers I've ever seen attached to
>>> a single try is 5 or 6. It there ever going to be a large enough
>>> number that the performance difference will be significant?
>>>
>> Possibly, in generated code. E.g. there are quite a large number of
>> possible HTTP return codes. If these got put into an errorCode {HTTP
>> 302 /redirected.html} then I can quite imagine HTTP client libraries
>> wanting large try statements and wanting fast lookup.
>>
> Fair case.
> But how will they do it now? I would imagine most developers would
> happily use a [switch], not realising that they are not getting O(1)
> performance out of it.
switch -exact is O(1), or should be.
>>> I think non-determinism in the syntax of a language is a very bad
>>> thing. Notice that even [switch] is documented as: "The switch
>>> command matches its string argument against each of the pattern
>>> arguments in order", so the behaviour is deterministic and
>> This is the point -- the behaviour isn't non-deterministic as it is
>> explicit what command is being used for matching, and the docs for
>> that command specify the ordering used. Non-determinism doesn't
>> require that [try] specify every last detail of execution -- it can
>> happily delegate those responsibilities.
>>
> The point is that irrespective of whether you are using -glob, -
> regex or
> -exact, you as a developer can scan the [switch] cases in left-to-
> right
> order and know that the first match will be the one that will be used.
> If [try] delegates its ordering then you cannot do this. You need to
> know the behaviour of "try -command mymatcher".
What's wrong with that? If I know it's try -matchcommand {switch -
glob --} then I know to expect left-to-right behaviour. If I know
it's something based on a hash lookup, then I know to expect only
exact matching.
>
> Given "try -command oo_matcher { .... } on error SomeException { ... }
> on error OtherException { ... }" it is reasonable to assume that
> you're
> matching on the class of the exception object, but if
> OtherException is
> a child of SomeException, which one will match?
That's up to oo_matcher. That's a good thing.
> Language syntax should
> enable you to determine that. Leaving it to a pluggable handler means
> that a novice developer or maintenance coder needs to understand every
> nuance of [try] and every matcher you use to understand the
> behaviour of
> a rather elementary control structure.
That argument applies to any command that takes a callback. You could
equally say that no-one can know the behaviour of [lsort -command]
without knowing every possible comparison function. Of course, it's
not a problem because the language syntax *does* make it obvious
which command is being used: You look at the -command/-matchcommand
option and examine the docs of the corresponding command.
-- 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.
|