From p.dalgaard at biostat.ku.dk  Thu Jul 30 11:12:58 2009
From: p.dalgaard at biostat.ku.dk (Peter Dalgaard)
Date: Thu, 30 Jul 2009 11:12:58 +0200
Subject: [Rd] Strange Interaction Between Promises and Closures
	(PR#13861)
In-Reply-To: <20090729175016.731F8282C76A@mail.pubhealth.ku.dk>
References: <20090729175016.731F8282C76A@mail.pubhealth.ku.dk>
Message-ID: <4A71641A.8080901@biostat.ku.dk>

kbare at andrew.cmu.edu wrote:
> Full_Name: Keith Bare
> Version: 2.7.1
> OS: Linux
> Submission from: (NULL) (128.2.134.48)
> 
> 
> I observed unexpected behavior attempting to use lapply to vary parameters in
> generated closures.  All the generated closures ran with the last parameter
> value in the list.
> 
> Here's a simple example:
> 
>> funcs <- lapply(c("alpha", "beta", "gamma", "delta"), function(x) function()
> print(x))
>> funcs[[1]]()
> [1] "delta"
>> funcs[[2]]()
> [1] "delta"
>> funcs[[3]]()
> [1] "delta"
>> funcs[[4]]()
> [1] "delta"
> 
> 
> What appears to be happening, is that the unevaluated promise for x is getting
> stored in the generated closure.  This promise references a variable in the
> local environment for the lapply call.  However, that variable gets clobbered by
> subsequent processing by lapply.
> 
> 
> This may be a language "feature" rather than a bug.  But IMO, the observed
> behavior is very non-intuitive.  If so, maybe it deserves mention in the
> documentation for lapply, "function", or the language reference section on
> functions.
> 
> 
> For now, I've found that adding a force in the function that generates the
> returned closure is a workaround.  E.g.:
> 
>> funcs <- lapply(c("alpha", "beta", "gamma", "delta"), function(x) { force(x);
> function() print(x) })
>> funcs[[1]]()
> [1] "alpha"
>> funcs[[2]]()
> [1] "beta"
>> funcs[[3]]()
> [1] "gamma"
>> funcs[[4]]()
> [1] "delta"

Not a bug, consequence of lazy evaluation, and force() IS the 
workaround. It is not specific to lapply; a prototypical example goes

 > f <- function(x) function() x
 > x <- 2
 > g <- f(x)
 > x <- 4
 > g()
[1] 4
 > x <- 6
 > g()
[1] 4

In the lapply context, the promise refers to an internal loop variable, 
and if the promise is not evaluated until the loop is done, you get the 
value of the loop variable at the end.

Documenting this sort of thing in a place that actually gets seen is an 
interesting problem... Probably, Section 4.3.3 in the R-lang manual is 
the only viable option.


-- 
    O__  ---- Peter Dalgaard             ?ster Farimagsgade 5, Entr.B
   c/ /'_ --- Dept. of Biostatistics     PO Box 2099, 1014 Cph. K
  (*) \(*) -- University of Copenhagen   Denmark      Ph:  (+45) 35327918
~~~~~~~~~~ - (p.dalgaard at biostat.ku.dk)              FAX: (+45) 35327907



[Rd] Strange Interaction Between Promises and Closures (PR#13861)
Peter Dalgaard