Any ideas? Is this a big or a deliberate feature? Hadley On Saturday, September 1, 2012, Winston Chang wrote:
> I'm running into some hard-to-understand behavior with the evaluation > environment when NextMethod is used. I'm using square-bracket indexing > into objects, and the evaluation environment of the expression inside > the square brackets seems to change depending on what kind of > comparison operators are used. > > This behavior happens when the following conditions are met (this is > what I've found; I'm sure that these aren't necessary and sufficient > conditions): > - I call a function from an attached package. > - The function uses square bracket indexing with a class that has its > own definition of the operator, such as `[.factor` or `[.POSIXct`. (If > a vector of numerics is used, the error doesn't happen.) > - The indexing function uses NextMethod("["). > - An S3 method is used within the square brackets. (When a regular > function is used, there's no error.) > - The S3 method is from a package that is an import for the original > function's package, but this package is not attached. (If the package > is attached, then the error doesn't happen because R finds the method > in the standard search path.) > - An operator like == is used. (If the %in% operator is used, the > error doesn't happen.) > > > This may sound very abstract. I've created a sample package that > illustrates the behavior. The package is called envtest, and it has a > function called envtest(), which uses an S3 method from the nlme > package. nlme is listed as an import. > > You can either clone the repository here: > https://github.com/wch/envtest > Or you can install it with devtools, using: > library(devtools) > dev_mode() > install_github('envtest', 'wch') > > > > The envtest() function tries to index into a factor in different ways, > and prints the output for each one. This is the content of the > function. (If you load it from the global environment, it won't have > the same error, since the issue has to do with an import): > > envtest <- function() { > dat <- data.frame(x = 0, y = 0) > f <- factor(c("a", "b")) > > # Print the starting data > cat("\nf : ") > cat(f) > > cat("\n\nTests with %in% operator ----------------------------") > > # OK > cat('\n"x" %in% Names(y ~ x, data = dat) : ') > cat("x" %in% Names(y ~ x, data = dat)) > > # OK: Save boolean values to idx, then use f[idx] > cat('\nidx <- "x" %in% Names(y ~ x, data = dat); f[idx] : ') > cat({idx <- "x" %in% Names(y ~ x, data = dat); f[idx]}) > > # OK: Use the expression with S3 function Names directly inside of [] > cat('\nf["x" %in% Names(y ~ x, data = dat)] : ') > cat(f["x" %in% Names(y ~ x, data = dat)]) > > > cat("\n\nTests with == operator ------------------------------") > > # OK > cat('\n"x" == Names(y ~ x, data = dat) : ') > cat("x" == Names(y ~ x, data = dat)) > > # OK: Save boolean values to idx, then use f[idx] > cat('\nidx <- "x" == Names(y ~ x, data = dat); f[idx] : ') > cat({idx <- "x" == Names(y ~ x, data = dat); f[idx]}) > > # Error: Use the expression with S3 function Names directly inside of [] > cat('\nf["x" == Names(y ~ x, data = dat)] : ') > cat(f["x" == Names(y ~ x, data = dat)]) > > invisible() > } > > > > This is what happens when I run the envtest() function. All the > indexing operations work, except the last one, where, inside the > square brackets, the == operator is used, and it calls the S3 method > from an imported package. > > > library(envtest) > > envtest() > f : 1 2 > > Tests with %in% operator ---------------------------- > "x" %in% Names(y ~ x, data = dat) : TRUE > idx <- "x" %in% Names(y ~ x, data = dat); f[idx] : 1 2 > f["x" %in% Names(y ~ x, data = dat)] : 1 2 > > Tests with == operator ------------------------------ > "x" == Names(y ~ x, data = dat) : FALSE TRUE > idx <- "x" == Names(y ~ x, data = dat); f[idx] : 2 > f["x" == Names(y ~ x, data = dat)] : Error in Names(y ~ > x, data = dat) : could not find function "Names" > > > When I set options(error=recover), it's possible to investigate the > environment where it's trying to evaluate the expression Names(....), > when it runs into the error: > > Enter a frame number, or 0 to exit > > 1: envtest() > 2: envtest.r#40: cat(f["x" == Names(y ~ x, data = dat)]) > 3: f["x" == Names(y ~ x, data = dat)] > 4: `[.factor`(f, "x" == Names(y ~ x, data = dat)) > 5: NextMethod("[") > 6: Names(y ~ x, data = dat) > > Selection: 5 > > Browse[1]> environment() > <environment: 0x104421a78> > Browse[1]> parent.env(environment()) > <environment: namespace:base> > Browse[1]> parent.env(parent.env(environment())) > <environment: R_GlobalEnv> > > > When == is used, it tries to evaluate the expression Names(....) in > the environment namespace:base, and it fails because it can't find the > function. > However, when %in% is used, it tries to evaluate the expression > Names(....) in the environment namespace:nlme, which makes more sense > to me. > > > Is this expected behavior? And if so, could someone explain why it > should be expected? I'm confused as to why the evaluation environment > should change when a certain narrow set of conditions is met. > > > -Winston > > ______________________________________________ > R-devel@r-project.org <javascript:;> mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel > -- Assistant Professor Department of Statistics / Rice University http://had.co.nz/ [[alternative HTML version deleted]] ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel