From ripley at stats.ox.ac.uk  Wed Oct 18 10:15:16 2006
From: ripley at stats.ox.ac.uk (Prof Brian Ripley)
Date: Wed, 18 Oct 2006 09:15:16 +0100 (BST)
Subject: [Rd] Error condition in evaluating a promise
In-Reply-To: <1BF71ED7-1F46-43F3-83BE-D353FC410BA6@r-project.org>
References: <0359A469-1F7D-4CEF-A408-CCB185D5F90E@r-project.org>
	<6phvemixy1u.fsf@gopher4.fhcrc.org>
	<1BF71ED7-1F46-43F3-83BE-D353FC410BA6@r-project.org>
Message-ID: <Pine.LNX.4.64.0610180856450.10475@gannet.stats.ox.ac.uk>

As is clear from the message you got, promises were originally implemented 
to handle lazy evaluation of closure arguments, as essentially transient 
objects.  There are several aspects of their implementation that are 
tailored to that use, one being that they can only be evaluated once (as a 
loop-detection test).

There is very little documentation on promises, mainly I believe because 
their use at R level is not encouraged.  There is documentation at C level 
in the R-ints.texi manual, including statements that make it clear that 
they can only be evaluated once.  Simple questions like exactly when a 
promise gets evaluated still don't have precise documented answers (and 
indeed we keep on finding errors in the code when they needed to be 
evaluated and were not).

I am not sure what you are really trying to do here: your example is very 
simple and does not (I guess) indicate the real application.  It is 
possible we could change the semantics only to stop re-evaluation during 
evaluation, and set a different flag on successful evaluation.

On Tue, 17 Oct 2006, Simon Urbanek wrote:

>
> On Oct 17, 2006, at 8:33 PM, Martin Morgan wrote:
>
>>> delayMe <- function() {
>> +     if (failed) {
>> +         delayedAssign("x", delayMe(), assign.env=topenv())
>> +         stop("init me!")
>> +     } else foo
>> + }
>>>
>>> failed <- TRUE
>>> foo <- "is me"
>>> delayedAssign("x", delayMe())
>>> x
>> Error in delayMe() : init me!
>>> x
>> Error in delayMe() : init me!
>>> failed <- FALSE
>>> x
>> [1] "is me"
>>
>> ??
>>
>
> This works only because you assigned both x and the delayMe function
> to the global environment. This won't work in any other case (and no,
> I didn't want to use this in the global environment - you shouldn't
> be trashing it anyway ;)).
>
> Of course you can recursively re-install the promise, but that's
> beside the point.
> FWIW a general solution re-installing the promise could look like this:
> local({ ae<-parent.env(environment()); d<-function() {print
> (environment()); if(failed) { delayedAssign("x", d(), assign.env=ae);
> stop("init me!") } else foo}; delayedAssign("x", d(),assign.env=ae)})
>
> However in my particular case the whole point of using a promise is
> that I'm dealing with a sealed environment (namespace) so you cannot
> re-install delayedAssign again (it will fail because the binding is
> locked). If the promise worked as I envision, re-installing
> delayedAssign would be unnecessary, because the promise is already in
> place and will stay there until the evaluation is successful.
>
> Cheers,
> Simon
>
>> Simon Urbanek <simon.urbanek at r-project.org> writes:
>>
>>> Is there a way to raise an error condition when a promise is
>>> evaluated such that is can be evaluated again? Right now strange
>>> things happen when the evaluation fails:
>>>
>>>> delayedAssign("x", if (failed) stop("you have to initialize me
>>> first!") else foo)
>>>> foo <- "I'm foo"
>>>> failed<-TRUE
>>>> x
>>> Error: you have to initialize me first!
>>>> x
>>> Error: recursive default argument reference
>>>
>>> ^^-- from now on x is completely unusable - it has no value (i.e.
>>> cannot be passed to any function) and yet won't be evaluated again
>>>
>>>> failed<-FALSE
>>>> x
>>> Error: recursive default argument reference
>>>> delayedAssign("x", if (failed) stop("you have to initialize me
>>> first!") else foo)
>>>> x
>>> [1] "I'm foo"
>>>
>>> I'd expect something like
>>>> failed<-TRUE
>>>> x
>>> Error: you have to initialize me first!
>>>> x
>>> Error: you have to initialize me first!
>>>> failed<-FALSE
>>>> x
>>> [1] "I'm foo"
>>>
>>> Is there a way to achieve that? Intuitively I'd think that this is
>>> the desired behavior, because currently the promise is sort of
>>> 'broken' after an error (AFAICT the behavior is not documented
>>> anywhere) - but then, I wasn't messing with promises until now...
>>>
>>> Thanks,
>>> Simon
>>>
>>> ______________________________________________
>>> R-devel at r-project.org mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>> --
>> Martin T. Morgan
>> Bioconductor / Computational Biology
>> http://bioconductor.org
>>
>>
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

-- 
Brian D. Ripley,                  ripley at stats.ox.ac.uk
Professor of Applied Statistics,  http://www.stats.ox.ac.uk/~ripley/
University of Oxford,             Tel:  +44 1865 272861 (self)
1 South Parks Road,                     +44 1865 272866 (PA)
Oxford OX1 3TG, UK                Fax:  +44 1865 272595




[Rd] Error condition in evaluating a promise
Prof Brian Ripley