[Rd] Possible documentation problem/bug?

Deepayan Sarkar deep@y@n@@@rk@r @end|ng |rom gm@||@com
Fri May 1 08:44:43 CEST 2020


On Thu, Apr 30, 2020 at 6:04 PM Dominic Littlewood
<11dlittlewood using 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* argument

Isn'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 using r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel



More information about the R-devel mailing list