Assuming you are fine with a pairlist instead of a list avoiding the `as.list()` call for dots2 saves a reasonable amount of time and makes it clearly the fastest.
library(rlang) dots1 <- function(...) as.list(substitute(list(...)))[-1L] dots2 <- function(...) as.list(substitute(...())) dots2.5 <- function(...) substitute(...()) dots3 <- function(...) match.call(expand.dots = FALSE)[["..."]] dots4 <- function(...) exprs(...) bench::mark( dots1(1+2, "a", rnorm(3), stop("bang!")), dots2(1+2, "a", rnorm(3), stop("bang!")), dots2.5(1+2, "a", rnorm(3), stop("bang!")), dots3(1+2, "a", rnorm(3), stop("bang!")), dots4(1+2, "a", rnorm(3), stop("bang!")), check = FALSE )[1:4] #> # A tibble: 5 x 4 #> expression min mean median #> <chr> <bch:tm> <bch:tm> <bch:tm> #> 1 "dots1(1 + 2, \"a\", rnorm(3), stop(\"bang!\… 2.38µs 5.63µs 2.89µs #> 2 "dots2(1 + 2, \"a\", rnorm(3), stop(\"bang!\… 2.07µs 3.1µs 2.6µs #> 3 "dots2.5(1 + 2, \"a\", rnorm(3), stop(\"bang… 471ns 789.5ns 638ns #> 4 "dots3(1 + 2, \"a\", rnorm(3), stop(\"bang!\… 3.17µs 4.83µs 4.22µs #> 5 "dots4(1 + 2, \"a\", rnorm(3), stop(\"bang!\… 3.16µs 4.43µs 3.87µs On Mon, Aug 13, 2018 at 7:59 PM Hadley Wickham <h.wick...@gmail.com> wrote: > Since you're already using bang-bang ;) > > library(rlang) > > dots1 <- function(...) as.list(substitute(list(...)))[-1L] > dots2 <- function(...) as.list(substitute(...())) > dots3 <- function(...) match.call(expand.dots = FALSE)[["..."]] > dots4 <- function(...) exprs(...) > > bench::mark( > dots1(1+2, "a", rnorm(3), stop("bang!")), > dots2(1+2, "a", rnorm(3), stop("bang!")), > dots3(1+2, "a", rnorm(3), stop("bang!")), > dots4(1+2, "a", rnorm(3), stop("bang!")), > check = FALSE > )[1:4] > #> # A tibble: 4 x 4 > #> expression min mean > median > #> <chr> <bch:tm> <bch:tm> > <bch:t> > #> 1 "dots1(1 + 2, \"a\", rnorm(3), stop(\"bang!\"… 3.23µs 4.15µs > 3.81µs > #> 2 "dots2(1 + 2, \"a\", rnorm(3), stop(\"bang!\"… 2.72µs 4.48µs > 3.37µs > #> 3 "dots3(1 + 2, \"a\", rnorm(3), stop(\"bang!\"… 4.06µs 4.94µs > 4.69µs > #> 4 "dots4(1 + 2, \"a\", rnorm(3), stop(\"bang!\"… 3.92µs 4.9µs > 4.46µs > > > On Mon, Aug 13, 2018 at 4:19 AM Henrik Bengtsson > <henrik.bengts...@gmail.com> wrote: > > > > Thanks all, this was very helpful. Peter's finding - dots2() below - > > is indeed interesting - I'd be curious to learn what goes on there. > > > > The different alternatives perform approximately the same; > > > > dots1 <- function(...) as.list(substitute(list(...)))[-1L] > > dots2 <- function(...) as.list(substitute(...())) > > dots3 <- function(...) match.call(expand.dots = FALSE)[["..."]] > > > > stats <- microbenchmark::microbenchmark( > > dots1(1+2, "a", rnorm(3), stop("bang!")), > > dots2(1+2, "a", rnorm(3), stop("bang!")), > > dots3(1+2, "a", rnorm(3), stop("bang!")), > > times = 10e3 > > ) > > print(stats) > > # Unit: microseconds > > # expr min lq mean median > > uq max neval > > # dots1(1 + 2, "a", rnorm(3), stop("bang!")) 2.14 2.45 3.04 2.58 > > 2.73 1110 10000 > > # dots2(1 + 2, "a", rnorm(3), stop("bang!")) 1.81 2.10 2.47 2.21 > > 2.34 1626 10000 > > # dots3(1 + 2, "a", rnorm(3), stop("bang!")) 2.59 2.98 3.36 3.15 > > 3.31 1037 10000 > > > > /Henrik > > > > On Mon, Aug 13, 2018 at 7:10 AM Peter Meilstrup > > <peter.meilst...@gmail.com> wrote: > > > > > > Interestingly, > > > > > > as.list(substitute(...())) > > > > > > also works. > > > > > > On Sun, Aug 12, 2018 at 1:16 PM, Duncan Murdoch > > > <murdoch.dun...@gmail.com> wrote: > > > > On 12/08/2018 4:00 PM, Henrik Bengtsson wrote: > > > >> > > > >> Hi. For any number of *known* arguments, we can do: > > > >> > > > >> one <- function(a) list(a = substitute(a)) > > > >> two <- function(a, b) list(a = substitute(a), b = substitute(b)) > > > >> > > > >> and so on. But how do I achieve the same when I have: > > > >> > > > >> dots <- function(...) list(???) > > > >> > > > >> I want to implement this such that I can do: > > > >> > > > >>> exprs <- dots(1+2) > > > >>> str(exprs) > > > >> > > > >> List of 1 > > > >> $ : language 1 + 2 > > > >> > > > >> as well as: > > > >> > > > >>> exprs <- dots(1+2, "a", rnorm(3)) > > > >>> str(exprs) > > > >> > > > >> List of 3 > > > >> $ : language 1 + 2 > > > >> $ : chr "a" > > > >> $ : language rnorm(3) > > > >> > > > >> Is this possible to achieve using plain R code? > > > > > > > > > > > > I think so. substitute(list(...)) gives you a single expression > containing > > > > a call to list() with the unevaluated arguments; you can convert > that to > > > > what you want using something like > > > > > > > > dots <- function (...) { > > > > exprs <- substitute(list(...)) > > > > as.list(exprs[-1]) > > > > } > > > > > > > > Duncan Murdoch > > > > > > > > > > > > ______________________________________________ > > > > R-devel@r-project.org mailing list > > > > https://stat.ethz.ch/mailman/listinfo/r-devel > > > > ______________________________________________ > > R-devel@r-project.org mailing list > > https://stat.ethz.ch/mailman/listinfo/r-devel > > > > -- > http://hadley.nz > > ______________________________________________ > R-devel@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel > [[alternative HTML version deleted]] ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel