It seems like there is no obvious way in the documentation to convert the expressions in the dots argument to a list without evaluating them. Say, if you want to have a function that prints all its arguments:> foo(abc$de, fg[h], i)abc$de fg[h] i ...then converting them to a list would be helpful. Using substitute(...) was the first thing I tried, but that only gives the *first *argument in dots. It turns out that there is a way to do this, using substitute(...()), but this does not appear to be in either the substitute or the dots help page. In fact, there is a clue how to do this in the documentation, if you look closely. Let me quote the substitute page: "Substituting and quoting often cause confusion when the argument is expression(...). The result is a call to the expression constructor function and needs to be evaluated with eval to give the actual expression object." So this appears to give a way to turn the arguments into a list - eval(substitute(expression(...))). But that's quite long, and hard to understand if you just come across it in some code - why are we using eval here? why are we substituting expression? - and would definitely require an explanatory comment. If the user just wants to iterate over the arguments, substitute(...()) is better. In fact, you can get exactly the same effect as the above code using as.expression(substitute(...())). Should the documentation be updated? [[alternative HTML version deleted]]
Le 30/04/2020 ? 14:31, Dominic Littlewood a ?crit?:> It seems like there is no obvious way in the documentation to convert > the expressions in the dots argument to a list without evaluating > them. Say, if you want to have a function that prints all its arguments:If you wish to iterate through all the arguments (not only '...') then match.call() seems to be the most straightforward and explicit tool: f=function(a, ...) {mc <- match.call(); print(as.list(mc)[-1])} f(x,y[h],abc$d) #$a #x # #[[2]] #y[h] # #[[3]] #abc$d Best, Serguei.> >> foo(abc$de, fg[h], i) > abc$de > fg[h] > i > > ...then converting them to a list would be helpful. > Using substitute(...) was the first thing I tried, but that only gives > the *first > *argument in dots. It turns out that there is a way to do this, using > substitute(...()), but this does not appear to be in either the substitute or > the dots help page. > > In fact, there is a clue how to do this in the documentation, if you look > closely. Let me quote the substitute page: > > "Substituting and quoting often cause confusion when the argument is > expression(...). The result is a call to the expression constructor > function and needs to be evaluated with eval to give the actual expression > object." > > So this appears to give a way to turn the arguments into a list - > eval(substitute(expression(...))). But that's quite long, and hard to > understand if you just come across it in some code - why are we using eval > here? why are we substituting expression? - and would definitely require an > explanatory comment. If the user just wants to iterate over the arguments, > substitute(...()) is better. In fact, you can get exactly the same effect > as the above code using as.expression(substitute(...())). Should the > documentation be updated? > > [[alternative HTML version deleted]] > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel
On Thu, Apr 30, 2020 at 6:04 PM Dominic Littlewood <11dlittlewood at gmail.com> wrote:> > It seems like there is no obvious way in the documentation to convert the > expressions in the dots argument to a list without evaluating them. Say, if > you want to have a function that prints all its arguments: > > > foo(abc$de, fg[h], i) > abc$de > fg[h] > i > > ...then converting them to a list would be helpful. > Using substitute(...) was the first thing I tried, but that only gives > the *first* argumentIsn't that what you would expect anyway? substitute() takes two arguments, the expression and an environment. You are giving it three. Normally this should be an error: foo <- function(a, b, c) substitute(a, b, c) foo(abc$de, fg[h], i) # Error in substitute(a, b, c) : unused argument (c) Clearly ... is being handled in some special way so that we don't get an error, but otherwise works as expected. foo <- function(...) substitute(...) foo(abc$de, fg[h], i) # abc$de I would consider this a side-effect of the implementation, and not something you should rely on. On the other hand, I would have expected the following to give something sensible, and it does: foo <- function(...) substitute({...}) foo(abc$de, fg[h], i) # { # abc$de # fg[h] # i # } as.character(foo(abc$de, fg[h], i)) # [1] "{" "abc$de" "fg[h]" "i"> in dots. It turns out that there is a way to do this, using > substitute(...()), but this does not appear to be in either the substitute or > the dots help page.There is no documented reason for this to work (AFAIK), so again, I would guess this is a side-effect of the implementation, and not a API feature you should rely on. This is somewhat borne out by the following:> foo <- function(...) substitute({...()}) > foo(abc$de, fg[h], i){ pairlist(abc$de, fg[h], i) }> foo(abc$de, fg[h], , i) # add a missing argument for extra fun{ as.pairlist(alist(abc$de, fg[h], , i)) } which is not something you would expect to see at the user level. So my recommendation: don't use ...() and pretend that you never discovered it in the first place. Use match.call() instead, as suggested by Serguei. [Disclaimer: I have no idea what is actually going on, so these are just guesses. There are some hints at https://cran.r-project.org/doc/manuals/r-devel/R-ints.html#Dot_002ddot_002ddot-arguments if you want to folllow up.] -Deepayan> In fact, there is a clue how to do this in the documentation, if you look > closely. Let me quote the substitute page: > > "Substituting and quoting often cause confusion when the argument is > expression(...). The result is a call to the expression constructor > function and needs to be evaluated with eval to give the actual expression > object." > > So this appears to give a way to turn the arguments into a list - > eval(substitute(expression(...))). But that's quite long, and hard to > understand if you just come across it in some code - why are we using eval > here? why are we substituting expression? - and would definitely require an > explanatory comment. If the user just wants to iterate over the arguments, > substitute(...()) is better. In fact, you can get exactly the same effect > as the above code using as.expression(substitute(...())). Should the > documentation be updated? > > [[alternative HTML version deleted]] > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel