On Tue, 11 Feb 2014, Romain Francois wrote:

Hello,

We have something very similar to your while loop in dplyr.
https://github.com/hadley/dplyr/blob/02a609310184d003c2ae9e0c013bfa69fa4d257a/inst/include/tools/DataDots.h#L15

because we need to know exactly in which environment a promise is supposed to 
be evaluated, even though we might combine standard R evaluation with an 
alternative faster engine. this is the basis of what we called hybrid 
evaluation.


For future work, I also have the while loop in the Promise class in Rcpp11, so 
that when you create a Promise in Rcpp11, its .environment() method gives you 
what you expect.
https://github.com/romainfrancois/Rcpp11/blob/master/inst/include/Rcpp/Promise.h#L14

So, this is something I find useful, although I’m not sure we are supposed to 
mess with promises.

No you are not :-)

Promises are an internal mechanism for implementing lazy
evaluation. They are convenient but also very inefficient, so they may
very well go away when a better approach becomes available.  What will
not go away is the functionality they provide -- bindings with
deferred evaluations, an expression/code for the evaluation, and an
environment (until the evaluation happens). If you build on those
concepts you will be more future proof than if you assume there will
be an internal promise object.

Best,

luke


Romain

Le 11 févr. 2014 à 19:02, Michael Lawrence <lawrence.mich...@gene.com> a écrit :

Hi all,

It seems that there is a use case for obtaining the environment for the
"top" promise. By "top", I mean following the promise chain up the call
stack until hitting a non-promise.

S4 data containers often mimic the API of base R data structures. This
means writing S4 methods for functions that quote their arguments, like
with() and subset(). The methods package directly forwards any arguments
not used for dispatch, so substitute(subset) is able to resolve the
original quoted argument (this is not the case for naively written
wrappers).  The problem then becomes figuring out the environment in which
to evaluate the expression.

Consider:

setClass("A", representation(df = "data.frame"))

setMethod("subset", "A", function(x, subset) {
 env <- parent.frame(2)
 x@df <- x@df[eval(substitute(subset), x@df, env),,drop=FALSE]
 x
})

dropLowMpg <- function(x, cutoff=20) {
 invisible(subset(x, mpg > cutoff))
}

a <- new("A", df=mtcars)
dropLowMpg(a)

The above works just fine, because we figured out that we need to evaluate
in the grand-parent frame to avoid the frame of the generic call. But now
let's assume A has a subclass B, and subset,B delegates to subset,A via
callNextMethod(). The call stack is different, and our assumption is
invalid.

setClass("B", representation(nrow="integer"), contains="A")
setMethod("subset", "B", function(x, ...) {
 ans <- callNextMethod()
 ans@nrow <- nrow(ans@df)
 ans
})
b <- new("B", df=mtcars)
dropLowMpg(b)
Error in eval(expr, envir, enclos) (from #3) : object 'cutoff' not found

We can fix this with a simple C function:
SEXP top_prenv(SEXP nm, SEXP env)
{
 SEXP promise = findVar(nm, env);
 while(TYPEOF(promise) == PROMSXP) {
   env = PRENV(promise);
   promise = PREXPR(promise);
 }
 return env;
}

With R wrapper:
top_prenv <- function(x) {
 .Call2("top_prenv", substitute(x), parent.frame())
}

Then this works (need to set subset,B again to reset cache):

setMethod("subset", "A", function(x, subset) {
 env <- top_prenv(subset)
 x@df <- x@df[eval(substitute(subset), x@df, env),,drop=FALSE]
 x
})
setMethod("subset", "B", function(x, ...) {
 ans <- callNextMethod()
 ans@nrow <- nrow(ans@df)
 ans
})

b <- new("B", df=mtcars)
dropLowMpg(b)

Would this be a useful addition to R? Is there a better way to solve this
issue? We're using this successfully in the IRanges package now, but we'd
like to avoid dealing with the internal details of R, and this is something
that could be of general benefit.

Thanks,
Michael

        [[alternative HTML version deleted]]

______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


--
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:   luke-tier...@uiowa.edu
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

Reply via email to