Hi,

It would be great if one of the experts could comment on the
difference between Hadley's dotlength and ...length? The fact
that someone bothered to implement a new primitive for that
when there seems to be a very simple and straightforward R-only
solution suggests that there might be some gotchas/pitfalls with
the R-only solution.

Thanks,
H.


On 05/03/2018 08:34 AM, Hadley Wickham wrote:
On Thu, May 3, 2018 at 8:18 AM, Duncan Murdoch <murdoch.dun...@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


--
Hervé Pagès

Program in Computational Biology
Division of Public Health Sciences
Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N, M1-B514
P.O. Box 19024
Seattle, WA 98109-1024

E-mail: hpa...@fredhutch.org
Phone:  (206) 667-5791
Fax:    (206) 667-1319

______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

Reply via email to