[Rd] delayedAssign changing values

peter dalgaard pdalgd at gmail.com
Fri Apr 27 01:37:53 CEST 2012

On Apr 27, 2012, at 00:10 , ghostwheel wrote:

> Simon Urbanek wrote
>>> More intuitive would have been the behavior
>>> delayedAssign("x", local({y <- 7; y+3}) ) 
>>> which only changes x.
>> That is questionable - I think it is more logical for both environments to
>> be the same as default. Just think if it -- the point here is to access
>> lazy evaluation which is exactly what it does - lazy evaluation takes
>> place in the original environment, not in another one.
> I think I finally understand. My intuition just came from looking at
> ?delayedAssign.
> But delayedAssign came to replace delay(), which "creates a promise to
> evaluate the given expression".
> When one thinks of delay(), what you said makes sense, you just delay
> executing a certain expression in the parent frame.
> I think, though, that with the current way it is described and called,
> delayedAssign should by default only have the side effect of changing the
> variable, i.e. use eval.env=new.env().

That's not possible. It involves evaluating an expression, and there is no limit to what side effect this can have.

> The manual states:
> This function is invoked for its side effect, which is assigning a promise
> to evaluate value to the variable x.
> I think that is a nice clear side effect - changing a variable when it is
> evaluated...like a delayed "<<-".
> Otherwise it seems to me that delayedAssign could cause debugging
> nightmares. Luckily, it currently doesn't seem to widely used to cause
> them....

Just don't do that, then.... However, lazy evaluation _per se_ does cause nightmares, or at least surprising behavior. My favorite one (because it actually involves a relevant piece of statistics) is

loglike <- function(x,n) function(p) dbinom(x, n, p, log=TRUE)
n <- 10
x <- 7
ll <- loglike(x, n)
x <- 1
curve(ll) # max at 0.1

which has the issue that x (and n too) is not evaluated until the ll function is called, at which time it may have been changed from the value it had when ll was created. 

> But you are right that it might be a bit strange that assign.env and
> eval.env are different. Maybe that is why there are two different parameters
> - to make the side effects clearer?
> I tried to find anywhere uses of delayedAssign which make positive use of
> side effects other than the assignment, and couldn't find any. Does anyone
> know of such a use?

They'll have to be rather contrived, but printing is one, and perhaps maintaining a count of function calls could be another.

> P.S. the end of ?delayedAssign contains this cryptic code:
> e <- (function(x, y = 1, z) environment())(1+2, "y", {cat(" HO! "); pi+2})
> (le <- as.list(e)) # evaluates the promises
> Which I think is another way to create a promise, other than delayedAssign.
> But it is really unclear why it sits there at the bottom of the document.
> There should probably be more explanation of what this is....

It's actually the _normal_ way to create a promise, namely binding actual arguments to formal arguments.  It is just that some trickery is used in order to make the situation visible. 

I agree that the example looks a bit out of place, though. Perhaps there ought to be a help page on lazy evaluation and a reference to it?  (Any volunteers?)

Peter Dalgaard, Professor,
Center for Statistics, Copenhagen Business School
Solbjerg Plads 3, 2000 Frederiksberg, Denmark
Phone: (+45)38153501
Email: pd.mes at cbs.dk  Priv: PDalgd at gmail.com

More information about the R-devel mailing list