[Rd] "try"ing to understand condition handling
ross at biostat.ucsf.edu
Tue Feb 20 23:35:40 CET 2007
Thanks; your response is very helpful. This message has some remarks
on my questions relative to the developer docs, one additional
question, and some documentation comments.
I'm really glad to hear you plan to revise the exception/condition
docs. since I found the existing ones a bit murky.
Below,  means
one of the documents Prof Ripley referred to.
That page also has a nice illustration of using the restart facility.
On Tue, Feb 20, 2007 at 01:40:11PM -0600, Luke Tierney wrote:
> On Mon, 19 Feb 2007, Ross Boylan wrote:
> >I'm confused by the page documenting tryCatch and friends.
> >I think it describes 3 separate mechanisms: tryCatch (in which control
> >returns to the invoking tryCatch), withCallHandlers (in which
should have been "withCallingHandlers"
> >goes up to the calling handler/s but then continues from the point at
> >which signalCondition() was invoked),
> unless a handler does a non-local exit, typically by invoking a restart
> >and withRestarts (I can't tell
> >where control ends up).
> at the withRestarts call
> >For tryCatch the docs say the arguments ... provide handlers, and that
> >these are matched to the condition. It appears that matching works by
> >providing entries in ... as named arguments, and the handler matches
> >if the name is one of the classes of the condition. Is that right? I
> >don't see the matching rule explicitly stated. And then the handler
> >itself is a single argument function, where the argument is the
>From , while discussing tryCatch,
Handlers are specified as
name = fun
where name specifies an exception class and fun is a function of one
argument, the condition that is to be handled.
> >Also, the documents don't explicitly say that the abstract subclasses
> >of 'error' and 'warning' are subclasses of 'condition', though that
> >seems to be implied and true.
The class relations are explicit in .
> >It appears that for tryCatch only the first matching handler is
> >executed, while for withCallHandlers all matching handlers are
> All handlers are executed, most recently established first, until
> there are none left or there is a transfer of control. Conceptually,
> exiting handlers established with tryCatch execute a transfer of
> control and then run their code.
Here's the one point of clarification: does the preceding paragraph
about "all handlers are executed" apply only to withCallingHandlers,
or does it include tryCatch as well? Rereading ?tryCatch, it still
looks as if the first match only will fire.
> Hopefully a more extensive document on this will get written in the
> next few months; for now the notes available off the developer page
> may be useful.
Great. FWIW, here are some suggestions about the documentation:
I would find a presentation that provided an overall orientation and
then worked down easiest to follow. So, goiing from the top down:
1. there are 3 forms of exception handling: try/catch, calling
handlers and restarts.
2. the characteristic behavior of each is ... (i.e., what's the flow
of control). Maybe give a snippet of typical uses of each.
3. the details (exact calling environment of the handler(s), matching
4. try() is basically a convenient form of tryCatch.
5. Other relations between these 3 forms: what happens if they are
nested; how restarts alter the "standard" control flow of the other
forms. I also found the info that the restart mechanism is the most
general and complicated useful for orientation (that might go under
It might be appropriate to document each form on a separate manual
page; I'm not sure if they are too linked (particularly by the use of
conditions and the control flow of restart) to make that a good idea.
I notice that some of the outline above is not the standard R manual
format; maybe the big picture should go in the language manual or on a
concept page (?Exceptions maybe).
Be explicit about the relations between conditions (class inheritance
Be explicit about how handlers are chosen and which forms they take.
It might be worth mentioning stuff that is a little surprising. The
fact that the value of the finally is not the value of the tryCatch
was a little surprising, since usually the value of a series of
statements or expression is that of the last one. The fact that
signalCondition can participate in two different flows of control
(discussion snipped above) was also surprising to me. In both cases
the current ?tryCatch is pretty explicit already, so that's not the
I found the current language (for ?tryCatch) about the calling context
of different handlers a bit obscure. For example, discussing tryCatch:
" If a handler
is found then control is transferred to the 'tryCatch' call that
established the handler, the handler found and all more recent
handlers are disestablished, the handler is called with the
condition as its argument, and the result returned by the handler
is returned as the value of the 'tryCatch' call."
It seems to me that control is transferred to within the tryCatch
call, rather than to the call itself. I'd expect transferring control
to the call to re-execute the whole thing, ad infinitum. I found the
seemingly less formal description in  easier to grasp:
" When an exception is signaled, the most recently established handler
that matches the exception (for which the exception inherits from the
specified class) is chosen, control transfers back to the try.catch
expression, the handler function is called, and the value returned by
the handler function is returned by the try.catch call. "
?tryCatch refers to "up" and "down" the stack in a few places.
Although there is really only one plausible reading, referring to
handlers established before or after the focal handler might be
clearer (at least in my head, I have an image of call stacks sometimes
going down in physical memory as they grow).
More information about the R-devel