On Tue, 20 Feb 2007, Ross Boylan wrote: > 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, [1] means > http://www.stat.uiowa.edu/~luke/R/exceptions/simpcond.html, > 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" >>> control >>> 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 >>> condition? > From [1], 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 [1]. > >>> >>> It appears that for tryCatch only the first matching handler is >>> executed, while for withCallHandlers all matching handlers are >>> executed. >> >> 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. > ....
Only to calling handlers because exiting ones conceptually execute a transfer of control out of the loop over the eligible handlers. [In principle tryCatch can be written in terms of withCallingHandlers using callCC to transfer control (callCC will be in R-devel shortly and corresponds to callcc in [1]). The expression tryCatch(expr, c1 = h1, c2 = h2) is essentially equivalent to something like (untested but hopefully close) cond <- NULL h <- NULL v <- callCC(function(k) withCallingHandlers(expr, c1 = function(c) { cond <<- c; h <<- h1; k(NULL)}, c2 = function(c) { cond <<- c; h <<- h2; k(NULL)})) if (is.null(h)) value else h(cond) Matching calling handlers are applied one at a time, but if one of these two matches then the call k(NULL) causes an immediate return from callCC with value NULL. If this doesn't help, ignore it.] >> >> 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. >> >> best, >> >> luke > 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 > rules, syntax...) > 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 > point 1). > > 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 > relations). > > 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 > issue. > > 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 [1] 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). > Thanks for the suggestions. Will keep them in mind for the revision. Best, luke > Ross > -- Luke Tierney Chair, Statistics and Actuarial Science Ralph E. Wareham Professor of Mathematical Sciences University of Iowa Phone: 319-335-3386 Department of Statistics and Fax: 319-335-3017 Actuarial Science 241 Schaeffer Hall email: [EMAIL PROTECTED] Iowa City, IA 52242 WWW: http://www.stat.uiowa.edu ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel