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 mailing list https://stat.ethz.ch/mailman/listinfo/r-devel