I have noticed dplyr/rlang changes if it can find value or not depending both on verb and execution context.
In this example we are looking for the value scale. If we try a mutate() while evaluating something from rlang::parse_text() while in a function we fail to find the value (I think this may also cause failures while knitting). However if we execute the code in the global environment we find the value. Also some other verbs (such as filter() do not show the same issue. The work-around I use is to use rlang:: parse_quosure() with direct control of the environment (which I also show here). However, given how irregular the behavior is (only happens in some contexts, and only for some verbs) I thought it might be important to file as it might help find some inconsistency in quoting or evaluation.
I am cross-filing to rlang and dplyr (as I think it may be an interaction) and I do not have the time to further simplify the example (though most of the length of the example is just demonstrating variations that work).
Edit: I had a typo in the original failing to show filter() works with rlang::parse_expr().
suppressPackageStartupMessages(library("dplyr"))
suppressPackageStartupMessages(library("glue"))
packageVersion("dplyr")
#> [1] '0.7.2'
packageVersion("rlang")
#> [1] '0.1.1.9000'
packageVersion("glue")
#> [1] '1.1.1'
mutate_se1 <- function(.data, mutateTerms) {
env <- parent.frame()
mutateQ <- lapply(mutateTerms,
function(si) {
rlang::parse_quosure(si,
env = env)
})
dplyr::mutate(.data = .data, !!!mutateQ)
}
mutate_se2 <- function(.data, mutateTerms) {
mutateQ <- lapply(mutateTerms,
function(si) {
rlang::parse_expr(si)
})
dplyr::mutate(.data = .data, !!!mutateQ)
}
d <- data.frame(x = 1:3,
g = c('a', 'a', 'b'),
stringsAsFactors = FALSE)
linkScoreCol <- 'x'
hello <- function() {
scale <- 2
print('mutate_se1')
d %>%
group_by(g) %>%
mutate_se1(list(prob =
glue('exp({linkScoreCol} * scale)/
sum(exp({linkScoreCol} * scale))'))) %>%
print()
print('mutate_se2')
tryCatch(
d %>%
group_by(g) %>%
mutate_se2(list(prob =
glue('exp({linkScoreCol} * scale)/
sum(exp({linkScoreCol} * scale))'))) %>%
print(),
error = function(e) {e}
)
}
hello()
#> [1] "mutate_se1"
#> # A tibble: 3 x 3
#> # Groups: g [2]
#> x g prob
#> <int> <chr> <dbl>
#> 1 1 a 0.1192029
#> 2 2 a 0.8807971
#> 3 3 b 1.0000000
#> [1] "mutate_se2"
#> <Rcpp::eval_error in mutate_impl(.data, dots): Evaluation error: non-numeric argument to binary operator.>
scale <- 2
d %>%
group_by(g) %>%
mutate_se2(list(prob =
glue('exp({linkScoreCol} * scale)/
sum(exp({linkScoreCol} * scale))'))) %>%
print()
#> # A tibble: 3 x 3
#> # Groups: g [2]
#> x g prob
#> <int> <chr> <dbl>
#> 1 1 a 0.1192029
#> 2 2 a 0.8807971
#> 3 3 b 1.0000000
Also filed as rlang issue 225.
the global environment is special. All namespaces inherit from it (and thus the whole search path). You need to use quosures to refer to variables in local environments.
I think you are parsing into a quosure in both versions of your filter reprexes.
That was a typo. I now see I had an additional type that I passed an environment to rlang::parse_expr(). Here is my issue: I have in fact seen the filter() correctly pick up constants in non-global environments. I first noticed this when re-building a pkgdown site that passed all R check yet rendered an error to pkdown when using filter and rlang::parse_expr(). I then re-built the pkgdown site with no code changes (and I think no package updates) and the code went back to executing without exception.
I don't have reproducible example at this point. The package was byte-compiled if that is relevant.
Please reopen if you find a reprex. Perhaps you had some variables defined in the global env after some interactive use?
Actually that sounds right. Probably pkgdown::build_site() isn't run in an isolated environment (so sees my globals, which are set as a side effect of trying to debug). That would explain everything I have seen, so no additional issues. Thanks!
Most helpful comment
Please reopen if you find a reprex. Perhaps you had some variables defined in the global env after some interactive use?