Closed egnha closed 6 years ago
quo()
quotes, so you get quos(x)
quoted, not evaluated. It's then evaluated by eval_tidy()
in an overscope. You found the proper way to do it: you need to unquote the parts that should be evaluated right away:
quo(!! quos(x))
By the way, you can post these questions on stackoverflow with the tidyeval tag and I'll get notifications.
Thanks for the clarification.
I notice now that the environment captured by eval_tidy(quo(quos(x)))
is a chain of two environments with empty frames, chained to the calling environment (global env, in this case):
q <- quo(quos(x))
e <- get_env(eval_tidy(q)[[1]])
chain <- Reduce(function(., ..) parent.env(.), 1:2, e, accumulate = TRUE)
chain
#> [[1]]
#> <environment: 0x7fd2f9bedc98>
#>
#> [[2]]
#> <environment: 0x7fd2f9bc97c8>
#>
#> [[3]]
#> <environment: R_GlobalEnv>
unlist(lapply(chain[1:2], ls, all.names = TRUE))
#> character(0)
I suppose this is by design (and I am guessing the intermediate environments are the bottom/top of an overscope), and that these environments are (mostly) harmless, vis-à-vis evaluation. But I still find it a bit puzzling that they are there, and I don't understand their purpose (i.e., why they are not "cleaned-up") ...
We have to return the bottom of the overscope because users might have created new values there, which might be later referred to if the quosure evaluates to a formula or a function (as these objects capture the dynamic environment in which they were evaluated).
The environments you see are empty because they were cleaned up after evaluation. But I guess we could rechain the bottom of the overscope to the environment of the outermost quosure to clean things further.
Thanks for the further clarification. That would be a welcome change, for I think it would help one to reason about quosures more consistently.
you can use env_parents()
by the way.
We no longer clean the overscope/data mask.
As intended,
quos()
captures the calling environment:But if you tidyeval a quosure of
quos()
, the calling environment is not passed on toquos()
; instead, some internally generated environment is captured (an overscope?):I would have expected
eval_tidy(quo(quos(x)))
to capture the global environment, asquos(x)
did (and aseval_tidy(quo(!! quos(x)))
would).Have I misunderstood something basic about the design/proper use of tidyeval?