From murdoch at stats.uwo.ca  Fri May 19 16:55:08 2006
From: murdoch at stats.uwo.ca (Duncan Murdoch)
Date: Fri, 19 May 2006 10:55:08 -0400
Subject: [Rd] delayedAssign and interrupts
In-Reply-To: <Pine.LNX.4.64.0605190920520.9980@nokomis.stat.uiowa.edu>
References: <446DCE07.2080504@gmail.com> <446DD2F8.5060900@stats.uwo.ca>
	<Pine.LNX.4.64.0605190920520.9980@nokomis.stat.uiowa.edu>
Message-ID: <446DDC4C.7040209@stats.uwo.ca>

On 5/19/2006 10:37 AM, Luke Tierney wrote:
> On Fri, 19 May 2006, Duncan Murdoch wrote:
> 
>> On 5/19/2006 9:54 AM, Roger D. Peng wrote:
>>> I noticed something recently that I thought was odd:
>>>
>>> delayedAssign("x", { Sys.sleep(5); 1 })
>>> x  ## Hit Ctrl-C within the first second or 2
>>>
>>> gives me:
>>>
>>> > delayedAssign("x", { Sys.sleep(5); 1 })
>>> > x  ## Hit Ctrl-C within the first second or two
>>>
>>> > x
>>> Error: recursive default argument reference
>>> >
>>>
>>> My only problem here is that now I'm stuck---there's no way to recover whatever
>>> 'x' was supposed to be (i.e. 1).
>>>
>>> In reality, I want 'x' to be a promise to load a moderately large data object.
>>> But if I (or a user) Ctrl-C's during the load I'll have to start from scratch.
>>> Is there anyway to recover the promise (or the value of the expression) in case
>>> of an interrupt?
>>
>> I don't know of one.  Normally substitute(x) is supposed to retrieve the
>>  promise expression, but by a strange quirk of history, it does not
>> work when x is in .GlobalEnv.
>>
>> I'd say the behaviour you're seeing is a bug.  If I do
>>
>> > x <- 2
>> > x <- {Sys.sleep(1); 1}  # Break before complete
>>
>> > x
>> [1] 2
>>
>> nothing is changed about x.  I would think the same thing should happen
>> when x is a promise:  if the evaluation of the promised expression
>> fails, the promise should not be changed.
> 
> I don't think this is a clear as you make it out--given that these
> uses of promises often have side effects, and some of those side
> effects may have occurred prior to an error, it isn't clear that
> pretending like no evaluation had happened is the right way to go.

Right, but the user would have seen the error, and can decide how to 
recover from it.  If trying to evaluate x again is the wrong thing to 
do, the user is the one who would know that.

> It should not be too hard to write a delayedAssignmentReset function
> if that is really useful; alternatively a user of delayedAssign should
> be able to arrange via tryCatch to chatch interrupts and re-install
> the delayed assignment if one occurs.
> 
> It might not be a bad idea for us to look into the promise evaluation
> internals and see if we should/can separate the promise black-holing
> from detection of recursive default argument references to get more
> reasonable error messages in these situations and maybe allow
> resetting more gnerally.  But anything done here had better keep
> efficiency in mind since this is prety core to R function call
> evaluation.  I may try to look into this when I get back to workign on
> R internals.

This is a very rare situation, so I agree putting in some slow way to 
recover from an error is a bad idea.  I think we should do the following:

  - fix substitute so it could be used to extract the promise expression 
even if x lives in .GlobalEnv.  (This can't happen for 2.3.1.)

  - add delayedAssignmentReset to repair x if that's preferred.  (Is 
this a reasonable addition to a patch release?)

This won't leave promises alone in case of an error, but will make it 
fairly easy for a user to recover using tryCatch.

Duncan



[Rd] delayedAssign and interrupts
Duncan Murdoch