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
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.
a+ : Opens a file for both appending and reading. ab+ : Opens a file for both appending and reading in binary mode.
closed is the member that tells you whether your file has been closed (which with does automatically), f. close() closes your file.
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.
Before performing substitution on any of its components, substitute()
first parses an R statement.
...()
parses to a call object, whereas ...
parses to a name object.
...
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))(...))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With