HenrikBengtsson / globals

🌐 R package: Identify Global Objects in R Expressions
https://globals.futureverse.org
28 stars 3 forks source link

findGlobals() chooses to be conservative when a variable is a global conditionally #31

Open HenrikBengtsson opened 6 years ago

HenrikBengtsson commented 6 years ago

Issue

findGlobals() choose to be conservative when a variable is a global conditionally on a run-time variable/value:

> findGlobals({ if (runif(1) < 1/2) y <- 0; y }, substitute = TRUE)
[1] "{"     "if"    "<"     "runif" "/"     "<-"

Here we probably want to pick up y as a global variable too.

I'm acknowledging that such ambiguous expression should be avoid, but we still might want to support them, and there might be cases where it could be argued for. Maybe the following is an example:

foo <- function(x, resample = FALSE) {
  idxs <- slow_creation_of_indices(x)  ## Make only once
  future_lapply(x, FUN = function(z) {
     if (resample) idxs <- sample(idxs)
     z[c(1,length(z))]
  })
}

Though it could be argued that what is really used here is:

foo <- function(x, resample = FALSE) {
  idxs0 <- slow_creation_of_indices(x)  ## Make only once
  future_lapply(x, FUN = function(z) {
     if (resample) idxs <- sample(idxs0) else idxs <- idxs0
     z[c(1,length(z))]
  })
}
HenrikBengtsson commented 6 years ago

Here's a miminal reproducible example that illustrates the problem and that can be used as a test case (in the future package).

library("future")
plan(multisession, workers = 2L)

reset <- TRUE
x <- 1
y %<-% { if (reset) x <- 0; x + 1 }
y
## [1] 1

reset <- FALSE
x <- 1
y %<-% { if (reset) x <- 0; x + 1 }
y
## Error: object 'x' not found
HenrikBengtsson commented 6 years ago

And for the record:

## Default
> globals::findGlobals({ if (reset) x <- 0; x + 1 }, method = "ordered", substitute = TRUE)
[1] "{"     "if"    "reset" "<-"    "+"    

> globals::findGlobals({ if (reset) x <- 0; x + 1 }, method = "conservative", substitute = TRUE)
[1] "{"     "if"    "reset" "<-"    "+"    

> globals::findGlobals({ if (reset) x <- 0; x + 1 }, method = "liberal", substitute = TRUE)
[1] "{"     "if"    "reset" "<-"    "+"     "x"    
HenrikBengtsson commented 6 years ago

Branch feature/if-ambiguity now has an initial prototype for handling this, e.g.

> globals::findGlobals({ if (reset) x <- 0; x + 1 }, method = "ordered", substitute = TRUE)
[1] "{"     "if"    "x"     "reset" "<-"    "+"

However, this does not appear to work when inside a function, e.g.

> globals::findGlobals(function() { if (reset) x <- 0; x + 1 }, method = "ordered", substitute = TRUE)
[1] "{"     "if"    "reset" "<-"    "+"

so more work is needed.

HenrikBengtsson commented 6 years ago

Previously, I've found one example of this in the caret package, and just now another example in the phylolm package (variable MLEsigma2_error).