length of `...`
On Thu, May 3, 2018 at 8:18 AM, Duncan Murdoch <murdoch.duncan at gmail.com> wrote:
On 03/05/2018 11:01 AM, William Dunlap via R-devel wrote:
In R-3.5.0 you can use ...length():
> f <- function(..., n) ...length()
> f(stop("one"), stop("two"), stop("three"), n=7)
[1] 3 Prior to that substitute() is the way to go
> g <- function(..., n) length(substitute(...()))
> g(stop("one"), stop("two"), stop("three"), n=7)
[1] 3 R-3.5.0 also has the ...elt(n) function, which returns the evaluated n'th entry in ... , without evaluating the other ... entries.
> fn <- function(..., n) ...elt(n)
> fn(stop("one"), 3*5, stop("three"), n=2)
[1] 15 Prior to 3.5.0, eval the appropriate component of the output of substitute() in the appropriate environment:
> gn <- function(..., n) {
+ nthExpr <- substitute(...())[[n]] + eval(nthExpr, envir=parent.frame()) + }
> gn(stop("one"), environment(), stop("two"), n=2)
<environment: R_GlobalEnv>
Bill, the last of these doesn't quite work, because ... can be passed down
through a string of callers. You don't necessarily want to evaluate it in
the parent.frame(). For example:
x <- "global"
f <- function(...) {
x <- "f"
g(...)
}
g <- function(...) {
firstExpr <- substitute(...())[[1]]
c(list(...)[[1]], eval(firstExpr, envir = parent.frame()))
}
Calling g(x) correctly prints "global" twice, but calling f(x) incorrectly
prints
[1] "global" "f"
You can get the first element of ... without evaluating the rest using ..1,
but I don't know a way to do this for general n in pre-3.5.0 base R.
If you don't mind using a package:
# works with R 3.1 and up
library(rlang)
x <- "global"
f <- function(...) {
x <- "f"
g(...)
}
g <- function(...) {
dots <- enquos(...)
eval_tidy(dots[[1]])
}
f(x, stop("!"))
#> [1] "global"
g(x, stop("!"))
#> [1] "global"
Hadley