Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confused by ...()?

Tags:

r

In another question, sapply(substitute(...()), as.character) was used inside a function to obtain the names passed to the function. The as.character part sounds fine, but what on earth does ...() do?

It's not valid code outside of substitute:

> test <- function(...) ...()
> test(T,F)
Error in test(T, F) : could not find function "..."

Some more test cases:

> test <- function(...) substitute(...())
> test(T,F)
[[1]]
T

[[2]]
F

> test <- function(...) substitute(...)
> test(T,F)
T
like image 666
Ari B. Friedman Avatar asked Sep 21 '12 02:09

Ari B. Friedman


People also ask

Have confused meaning?

feeling or exhibiting an inability to understand; bewildered; perplexed. 2. in a disordered state; mixed up; jumbled. 3. lacking sufficient mental abilities for independent living, esp through old age.

What is A+ mode in Python?

a+ : Opens a file for both appending and reading. ab+ : Opens a file for both appending and reading in binary mode.

What is the difference between file closed and file close ()?

closed is the member that tells you whether your file has been closed (which with does automatically), f. close() closes your file.


1 Answers

Here's a sketch of why ...() works the way it does. I'll fill in with more details and references later, but this touches on the key points.

  1. Before performing substitution on any of its components, substitute() first parses an R statement.

  2. ...() parses to a call object, whereas ... parses to a name object.

  3. ... is a special object, intended only to be used in function calls. As a consequence, the C code that implements substitution takes special measures to handle ... when it is found in a call object. Similar precautions are not taken when ... occurs as a symbol. (The relevant code is in the functions do_substitute, substitute, and substituteList (especially the latter two) in R_SRCDIR/src/main/coerce.c.)

So, the role of the () in ...() is to cause the statement to be parsed as a call (aka language) object, so that substitution will return the fully expanded value of the dots. It may seem surprising that ... gets substituted for even when it's on the outside of the (), but: (a) calls are stored internally as list-like objects and (b) the relevant C code seems to make no distinction between the first element of that list and the subsequent ones.


Just a side note: for examining behavior of substitute or the classes of various objects, I find it useful to set up a little sandbox, like this:

f <- function(...) browser()
f(a = 4, 77, B = "char")
## Then play around within the browser
class(quote(...))  ## quote() parses without substituting
class(quote(...()))
substitute({...})
substitute(...(..., X, ...))
substitute(2 <- (makes * list(no - sense))(...))
like image 177
Josh O'Brien Avatar answered Oct 08 '22 00:10

Josh O'Brien